#if defined(TSINGMA_MX) || defined(TSINGMA_GX) || defined(ARCTIC)

#include "sal_types.h"
#include "sal.h"
#include "sys_usw_acl.h"
#include "sys_usw_acl_extract.h"

extern sys_acl_master_t* p_usw_acl_master[CTC_MAX_LOCAL_CHIP_NUM_PP];
extern char* ifp_field_str[];

#define SYS_ACL_KEXT_SELCODE_DONT_CARE (-1)
#define SYS_ACL_KEXT_GRAN_SIZE 5
#define SYS_ACL_KEXT_SEC_PASSTHRU (1 << 0)
#define SYS_ACL_KEXT_F_WORD_CNT 1
#define SYS_ACL_KEXT_FIELDS_MAX 100
#define SYS_ACL_KEXT_GRAN_COUNT 5
#define SYS_ACL_KEXT_F_OFFSET_MAX 128
#define SYS_ACL_KEXT_F_OFFSET_COUNT 16
#define SYS_ACL_KEXT_F_USE_L2_GRAN16  (1 << 0)
#define SYS_ACL_KEXT_F_USE_L2_GRAN8   (1 << 1)
#define ORDER_TYPE_ASCENDING     (1 << 0)
#define ORDER_TYPE_DESCENDING    (1 << 1)
#define ORDER_TYPE_END_OF_LIST   (1 << 2)
#define ORDER_TYPE_START_OF_LIST (1 << 3)

STATIC uint8 debug_enable = 0;
STATIC uint16 finfo_free_count = 0;
STATIC uint16 finfo_used_count = 0;

#define DUMP_FINFO_COUNT(free) {  \
    if (free) {                   \
        if (debug_enable) {       \
            finfo_free_count++;   \
            finfo_used_count--;   \
        }                         \
    } else {                      \
        if (debug_enable) {       \
            finfo_free_count--;   \
            finfo_used_count++;   \
        }                         \
    }                             \
}


#ifdef ACL_PROGRAM_DBG
#define SYS_ACL_DBG_PRINT(FMT, ...)   sal_printf(FMT, ## __VA_ARGS__)
#define SYS_ACL_EXT_DBG(FMT, ...)   sal_printf(FMT, ## __VA_ARGS__)
const char* sys_acl_sec_str[] = {
    "DISABLE",
    "L1E32",
    "L1E16",
    "L1E8",
    "L1E4",
    "L1E2",
    "L2S1",
    "L2S2",
    "L3S1",
    "L3S2",
    "L2AS1",
    "L2AS2",
    "L2BS1",
    "L2BS2",
    "L2CS1",
    "L2CS2",
    "L3AS1",
    "L3AS2",
    "L3BS1",
    "L3BS2",
    "L3CS1",
    "L3CS2",
    "FK",
    "FKA",
    "FKB",
    "FKC",
    "COUNT"
};
#else
#define SYS_ACL_EXT_DBG(FMT, ...)
#define SYS_ACL_DBG_PRINT(FMT, ...) 
#endif

typedef struct sys_acl_kfield_info_s
{
    uint32 flags;
    uint8 partial;
    sys_acl_field_t field_id;
    uint32 bitmap[SYS_ACL_KFIELD_BITMAP_MAX_WORDS];
}
sys_acl_kfield_info_t;


typedef struct sys_acl_kfield_offset_s
{
    uint8 num_offsets;
    uint16 offset[SYS_ACL_KFIELD_OFFSETS_MAX];
    uint8 width[SYS_ACL_KFIELD_OFFSETS_MAX];
}
sys_acl_kfield_offset_t;


typedef struct sys_acl_kfield_offset_info_s
{
    sys_acl_field_t *qid_arr;
    sys_acl_kfield_offset_t *offset_arr;
    uint16 size;        /*key field num except ltid*/
}
sys_acl_kfield_offset_info_t;


typedef struct sys_acl_keygen_cfg_s
{
    uint32 flags;
    uint8 field_info_count;
    uint8 num_parts;
    uint16 ext_ctrl_sel_info_count;

    sys_acl_keygen_mode_t mode;
    sys_acl_kfield_info_t *field_info_arr;
    sys_acl_kfield_cfg_info_db_t *field_cfg_info_db;
    sys_acl_kext_cfg_db_t *ext_cfg_db;
    sys_acl_kext_ctrl_sel_info_t *ext_ctrl_sel_info;
}
sys_acl_keygen_cfg_t;

typedef struct sys_acl_keygen_oper_s
{
    sys_acl_kfield_offset_info_t *field_offset_info;
    sys_acl_kext_ctrl_sel_info_t *ext_ctrl_sel_info;
    uint16 ext_ctrl_sel_info_count;
}
sys_acl_keygen_oper_t;

typedef struct sys_acl_kext_sel_s
{
    int8  sel_ctl[SYS_ACL_KEXT_CTRL_SEL_MAX];
}
sys_acl_kext_sel_t;

typedef struct sys_acl_kext_sec_gran_s
{
    uint8 gran;
    uint8 num_extractors;
}
sys_acl_kext_sec_gran_t;

typedef struct sys_acl_kext_sec_gran_info_s
{
    sys_acl_kext_sec_gran_t  out_gran_info[SYS_ACL_KEXT_GRAN_SIZE];
    uint8 out_gran_info_count;
    sys_acl_kext_sec_gran_t  in_gran_info[SYS_ACL_KEXT_GRAN_SIZE];
    uint8 in_gran_info_count;
}
sys_acl_kext_sec_gran_info_t;

typedef struct sys_acl_kext_f_offset_s
{
    uint16 offset;
    uint16 width;
    uint8 chunk_id;
}
sys_acl_kext_f_offset_t;


typedef struct  sys_acl_kext_f_offset_info_s
{
    uint16 offset_count;
    sys_acl_kext_f_offset_t offsets[SYS_ACL_KEXT_F_OFFSET_MAX];
}
sys_acl_kext_f_offset_info_t;

typedef struct sys_acl_kext_f_s
{
    sys_acl_kext_sec_t section;
    uint8 sec_val;
    uint16 offset;
    uint8 width;
    uint32 req_bmp[SYS_ACL_KEXT_F_WORD_CNT];
    uint32 rsp_bmp[SYS_ACL_KEXT_F_WORD_CNT];
}
sys_acl_kext_f_t;


typedef struct sys_acl_kext_finfo_s
{
    uint32 flags;
    uint8 extracted;
    int8 part;
    int8 fixed;
    int16 qaul_id;
    sys_acl_kext_sec_t section;
    uint8 sec_val;
    uint8 size;
    uint8 req_bit_count;
    uint32 req_bmp[SYS_ACL_KEXT_F_WORD_CNT];
    uint32 ext_bmp[SYS_ACL_KEXT_F_WORD_CNT];
    sys_acl_kext_sec_t l0_section;
    uint8 l0_sec_val;
    uint16 l0_field_offset;
    sys_acl_kext_ctrl_sel_t pri_ctrl_sel;
    uint16 pri_ctrl_sel_val;
    sys_acl_kext_cfg_t *ext_cfg;
    uint8 prev_offset;

    uint8 half_flag;

    struct sys_acl_kext_finfo_s *prev;
    struct sys_acl_kext_finfo_s *next;

}
sys_acl_kext_finfo_t;

typedef struct sys_acl_kext_f_info_db_s
{
    sys_acl_kext_finfo_t *finfo[SYS_ACL_KEXT_SECTION_COUNT];
}
sys_acl_kext_f_info_db_t;

typedef sys_acl_kext_sec_t sys_acl_kext_sec_list_t[SYS_ACL_KEXT_SECTION_COUNT];


sys_acl_kext_finfo_t *finfo_free_list[CTC_MAX_LOCAL_CHIP_NUM_PP];
sys_acl_kext_finfo_t* p_finfo_pool[CTC_MAX_LOCAL_CHIP_NUM_PP];


typedef struct sys_acl_keygen_md_s
{
    sys_acl_kfield_cfg_info_t *field_cfg_info[SYS_ACL_FIELD_COUNT];
    sys_acl_kfield_cfg_info_db_t *field_cfg_info_db[SYS_ACL_KEXT_LEVEL_COUNT];
    sys_acl_kext_cfg_db_t *ext_cfg_db;
    uint8 *field_cfg_id_arr;
    uint32 field_cfg_combinations;
    sys_acl_kext_sec_list_t sections[SYS_ACL_KEYGEN_ENTRY_PARTS_MAX][SYS_ACL_KEXT_LEVEL_COUNT];
    sys_acl_kext_sec_gran_info_t section_gran_info[SYS_ACL_KEXT_SECTION_COUNT];
    sys_acl_kext_sel_t ext_codes[SYS_ACL_KEYGEN_ENTRY_PARTS_MAX];
    sys_acl_kext_finfo_t finfo[SYS_ACL_KEXT_FIELDS_MAX];
    sys_acl_kext_f_info_db_t ext_finfo_db[SYS_ACL_KEYGEN_ENTRY_PARTS_MAX][SYS_ACL_KEXT_LEVEL_COUNT];
    uint32 bits_extracted[SYS_ACL_KEYGEN_ENTRY_PARTS_MAX][SYS_ACL_KEXT_GRAN_COUNT];
    uint8 tried_part_bmp[SYS_ACL_KEXT_GRAN_COUNT];
    uint8 num_ext_levels;
    sys_acl_kext_f_offset_info_t offset_info;
}
sys_acl_keygen_md_t;



#define SYS_ACL_EXT_SELCODE_DONT_CARE    (-1)
#define SYS_ACL_EXT_SELCODE_DONT_USE     (-2)


#define SYS_ACL_QSET_INIT(kset)   sal_memset(&(kset), 0, sizeof(sys_acl_kset_t))
#define SYS_ACL_QSET_ADD(kset, q)  CTC_BMP_SET(((kset).w), (q))
#define SYS_ACL_QSET_REMOVE(kset, q)  CTC_BMP_UNSET(((kset).w), (q))
#define SYS_ACL_QSET_TEST(kset, q)  CTC_BMP_ISSET(((kset).w), (q))
#define SYS_ACL_QSET_COPY(to_kset, from_kset) sal_memcpy((to_kset).w, (from_kset).w, sizeof (sys_acl_kset_t))



int32
sys_acl_kext_cfg_t_init(int32 lchip, sys_acl_kext_cfg_t *ext_cfg)
{
    STS_ACL_FUNC_ENTER(lchip);
    STS_ACL_NULL_CHECK(ext_cfg, CTC_E_INVALID_PARAM);
    sal_memset(ext_cfg, 0, sizeof(sys_acl_kext_cfg_t));
exit:
    STS_ACL_FUNC_EXIT();
}


STATIC int32
sys_acl_kext_cfg_add(int32 lchip,
                 uint8 level,
                 sys_acl_kext_cfg_t *new_ext_cfg,
                 sys_acl_kext_cfg_db_t *ext_cfg_db)
{
    uint32 size = 0;
    sys_acl_kext_cfg_t *ext_cfg = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(new_ext_cfg, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(ext_cfg_db, CTC_E_INVALID_PARAM);

    size = (ext_cfg_db->conf_size[level] + 1)  * sizeof(sys_acl_kext_cfg_t);
    SYS_ACL_ALLOC(ext_cfg, size);

    if (ext_cfg_db->ext_cfg[level] != NULL)
    {
        size -= sizeof(sys_acl_kext_cfg_t);
        sal_memcpy(ext_cfg, ext_cfg_db->ext_cfg[level], size);
        STS_ACL_FREE(ext_cfg_db->ext_cfg[level]);
    }
    else
    {
        ext_cfg_db->num_ext_levels++;
    }

    ext_cfg_db->ext_cfg[level] = ext_cfg;
    ext_cfg_db->ext_cfg[level][ext_cfg_db->conf_size[level]] = *new_ext_cfg;
    ext_cfg_db->conf_size[level]++;
    STS_ACL_FUNC_EXIT();

exit:
    STS_ACL_FREE(ext_cfg);
    STS_ACL_FREE(ext_cfg_db);
    STS_ACL_FUNC_EXIT();
}

STATIC int32
sys_acl_kext_sec_cfg_add(int32 lchip,
                     uint8 level,
                     sys_acl_kext_cfg_t *new_ext_cfg,
                     sys_acl_kext_cfg_db_t *ext_cfg_db)
{
    uint8 gran = 0;
    uint32 size = 0;
    sys_acl_kext_sec_t in_section;
    sys_acl_kext_sec_cfg_t *sec_cfg = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(new_ext_cfg, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(ext_cfg_db, CTC_E_INVALID_PARAM);

    in_section = new_ext_cfg->in_sec;
    sec_cfg = ext_cfg_db->sec_cfg[in_section];
    gran = SYS_ACL_KEXT_ID_GRAN_GET(new_ext_cfg->ext_id);

    if (sec_cfg == NULL)
    {
        size = sizeof(sys_acl_kext_sec_cfg_t);
        SYS_ACL_ALLOC(sec_cfg, size);
        sec_cfg->sec = new_ext_cfg->in_sec;
        sec_cfg->parent_sec = new_ext_cfg->in_sec;
        sec_cfg->drain_bits = gran;
        ext_cfg_db->num_sec++;
        ext_cfg_db->sec_cfg[in_section] = sec_cfg;
    }
    else
    {
        sec_cfg->drain_bits += gran;
    }

    if (CTC_BMP_ISSET(new_ext_cfg->ext_attrs.w, SYS_ACL_KEXT_ATTR_PASS_THRU))
    {
        sec_cfg->flags = SYS_ACL_KEXT_SEC_PASSTHRU;
    }

    STS_ACL_FUNC_EXIT();

exit:
    STS_ACL_FREE(sec_cfg);
    STS_ACL_FUNC_EXIT();
}


int32
sys_acl_kext_cfg_insert(int32 lchip,
                     uint8 level,
                     sys_acl_kext_cfg_t *ext_cfg,
                     sys_acl_kext_cfg_db_t *ext_cfg_db)
{
    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(ext_cfg, CTC_E_INVALID_PARAM);

    if (level < SYS_ACL_KEXT_LEVEL_COUNT)
    {
        STS_ACL_IF_ERR_EXIT(
        sys_acl_kext_cfg_add(lchip, level, ext_cfg, ext_cfg_db));
    }

    STS_ACL_IF_ERR_EXIT(
        sys_acl_kext_sec_cfg_add(lchip, level, ext_cfg, ext_cfg_db));

exit:
    STS_ACL_FUNC_EXIT();
}


int32
sys_acl_kfield_cfg_t_init(int32 lchip, sys_acl_kfield_cfg_t *field_cfg)
{
    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(field_cfg, CTC_E_INVALID_PARAM);

    sal_memset(field_cfg, 0, sizeof(sys_acl_kfield_cfg_t));

exit:
    STS_ACL_FUNC_EXIT();
}

int32
sys_acl_kfield_cfg_insert(int32 lchip,
                 uint32 field_id,
                 sys_acl_kfield_cfg_t *new_field_cfg,
                 sys_acl_kfield_cfg_info_db_t *field_cfg_info_db)
{
    uint8 field_cfg_info_db_alloc = 0;
    uint8 field_cfg_info_alloc = 0;
    uint8 chunk = 0;
    uint8 num_field_cfg = 0;
    sys_acl_kfield_cfg_t *field_cfg = NULL;
    sys_acl_kfield_cfg_t *field_cfg_arr = NULL;
    sys_acl_kfield_cfg_info_t *field_cfg_info = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(new_field_cfg, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(field_cfg_info_db, CTC_E_INVALID_PARAM);

    field_cfg_info = field_cfg_info_db->field_cfg_info[field_id];

    if (field_cfg_info == NULL)
    {
        SYS_ACL_ALLOC(field_cfg_info,
                      sizeof(sys_acl_kfield_cfg_info_t));
        field_cfg_info_db->field_cfg_info[field_id] = field_cfg_info;
        field_cfg_info->field = field_id;
        field_cfg_info_alloc = 1;
    }

    num_field_cfg = field_cfg_info->num_field_cfg + 1;

    SYS_ACL_ALLOC(field_cfg_arr,  num_field_cfg * sizeof(sys_acl_kfield_cfg_t));

    sal_memcpy(field_cfg_arr, field_cfg_info->field_cfg_arr,
               sizeof(sys_acl_kfield_cfg_t) * (num_field_cfg - 1));

    new_field_cfg->size = 0;
    field_cfg = &(field_cfg_arr[num_field_cfg - 1]);
    new_field_cfg->size = 0;

    for (chunk = 0; chunk < new_field_cfg->num_chunks; chunk++)
    {
        if (SYS_ACL_KEXT_SECTION_L1E32 == new_field_cfg->e_params[chunk].section)
        {
            new_field_cfg->e_params[chunk].size = 32;
        }
        else if (SYS_ACL_KEXT_SECTION_L1E16 == new_field_cfg->e_params[chunk].section)
        {
            new_field_cfg->e_params[chunk].size = 16;
        }
        else if (SYS_ACL_KEXT_SECTION_L1E8 == new_field_cfg->e_params[chunk].section)
        {
            new_field_cfg->e_params[chunk].size = 8;
        }
        else if (SYS_ACL_KEXT_SECTION_L1E4 == new_field_cfg->e_params[chunk].section)
        {
            new_field_cfg->e_params[chunk].size = 4;
        }
        else if (SYS_ACL_KEXT_SECTION_L1E2 == new_field_cfg->e_params[chunk].section)
        {
            new_field_cfg->e_params[chunk].size = 2;
        }

        new_field_cfg->size += new_field_cfg->e_params[chunk].width;
    }

    sal_memcpy(field_cfg, new_field_cfg, sizeof(sys_acl_kfield_cfg_t));

    STS_ACL_FREE(field_cfg_info->field_cfg_arr);

    field_cfg_info->field_cfg_arr = field_cfg_arr;
    field_cfg_info->num_field_cfg++;

    STS_ACL_FUNC_EXIT();

exit:
    STS_ACL_FREE(field_cfg_arr);

    if (field_cfg_info_db_alloc)
    {
        STS_ACL_FREE(field_cfg_info_db);
    }

    if (field_cfg_info_alloc)
    {
        STS_ACL_FREE(field_cfg_info);
    }
    STS_ACL_FUNC_EXIT();
}




STATIC int32
sys_acl_kext_finfo_db_free(int32 lchip,
                             uint8 part,
                             uint8 level,
                             sys_acl_keygen_md_t *keygen_md)
{
    sys_acl_kext_sec_t section;
    sys_acl_kext_finfo_t *finfo = NULL;
    sys_acl_kext_finfo_t *next_finfo = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);

    for (section = 0; section < SYS_ACL_KEXT_SECTION_COUNT; section++)
    {
        finfo = keygen_md->ext_finfo_db[part][level].finfo[section];

        while (finfo != NULL)
        {
            next_finfo = finfo->next;
            sal_memset(finfo, 0, sizeof(sys_acl_kext_finfo_t));
            finfo->next = finfo_free_list[lchip];
            finfo_free_list[lchip] = finfo;
            DUMP_FINFO_COUNT(1);
            finfo = next_finfo;
        }

        keygen_md->ext_finfo_db[part][level].finfo[section] = NULL;
    }

exit:
    STS_ACL_FUNC_EXIT();
}

STATIC int32
sys_acl_kext_cfg_reset_part(int32 lchip,
                             uint8 part,
                             sys_acl_keygen_cfg_t *keygen_cfg,
                             sys_acl_keygen_md_t *keygen_md)
{
    uint8 level = 0;
    uint8 ext_part = 0;
    uint16 ext_idx = 0;
    sys_acl_kext_sec_t section;
    sys_acl_kext_cfg_t *ext_cfg = NULL;
    sys_acl_kext_sec_cfg_t *sec_cfg = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);

    for (section = SYS_ACL_KEXT_SECTION_L1E32;
        section < SYS_ACL_KEXT_SECTION_COUNT;
    section++)
    {
        sec_cfg = keygen_md->ext_cfg_db->sec_cfg[section];
        if (sec_cfg != NULL)
        {
            sec_cfg->fill_bits = 0;
        }
    }

    for (level = 0; level <= keygen_md->num_ext_levels; level++)
    {
        for (ext_idx = 0; ext_idx < keygen_md->ext_cfg_db->conf_size[level]; ext_idx++)
        {
            ext_cfg =  keygen_md->ext_cfg_db->ext_cfg[level] + ext_idx;
            ext_part = SYS_ACL_KEXT_ID_PART_GET(ext_cfg->ext_id);

            if (part != ext_part)
            {
                continue;
            }

            if (CTC_BMP_ISSET(ext_cfg->ext_attrs.w, SYS_ACL_KEXT_ATTR_NOT_WITH_QSET_UPDATE))
            {
                sec_cfg = keygen_md->ext_cfg_db->sec_cfg[ext_cfg->in_sec];
                sec_cfg->fill_bits +=
                SYS_ACL_KEXT_ID_GRAN_GET(ext_cfg->ext_id);
                continue;
            }

            ext_cfg->in_use = FALSE;
            ext_cfg->finfo = NULL;
        }
    }

exit:
    STS_ACL_FUNC_EXIT();
}





STATIC void
sys_acl_kext_finfo_release(int32 lchip,
                             sys_acl_kext_finfo_t *finfo)
{
    sys_acl_kext_finfo_t *temp_finfo = NULL;

    while (finfo != NULL)
    {
        temp_finfo = finfo;
        finfo = finfo->next;
        sal_memset(temp_finfo, 0, sizeof(sys_acl_kext_finfo_t));
        temp_finfo->next = finfo_free_list[lchip];
        finfo_free_list[lchip] = temp_finfo;
        DUMP_FINFO_COUNT(1);
    }
}



STATIC int32
sys_acl_kext_validate(int32 lchip,
                       uint8 part,
                       sys_acl_keygen_md_t *keygen_md,
                       sys_acl_kext_cfg_t *ext_cfg)
{
    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(ext_cfg, CTC_E_INVALID_PARAM);

    if (ext_cfg->in_use == TRUE) {
        STS_ACL_RETURN_VAL_EXIT(CTC_E_INVALID_CONFIG);
    }
exit:
    STS_ACL_FUNC_EXIT();
}


STATIC int32
sys_acl_kfield_cfg_max_size_get(int32 lchip,
                            sys_acl_keygen_cfg_t *keygen_cfg,
                            sys_acl_field_t field_id,
                            uint16 *field_cfg_max_size)
{
    uint8 field_cfg_id = 0;
    uint8 field_cfg_chunk_id = 0;
    uint16 field_cfg_size = 0;
    sys_acl_kfield_cfg_t *field_cfg = NULL;
    sys_acl_kfield_cfg_info_t *field_cfg_info = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(field_cfg_max_size, CTC_E_INVALID_PARAM);

    *field_cfg_max_size = 0;

    field_cfg_info = keygen_cfg->field_cfg_info_db->field_cfg_info[field_id];

    for (field_cfg_id = 0;  field_cfg_id < field_cfg_info->num_field_cfg;  field_cfg_id++)
    {
        field_cfg = &(field_cfg_info->field_cfg_arr[field_cfg_id]);
        field_cfg_size = 0;

        for (field_cfg_chunk_id = 0; field_cfg_chunk_id < field_cfg->num_chunks;  field_cfg_chunk_id++)
        {
            field_cfg_size += field_cfg->e_params[field_cfg_chunk_id].width;
        }

        if (*field_cfg_max_size < field_cfg_size)
        {
            *field_cfg_max_size = field_cfg_size;
        }
    }

exit:
    STS_ACL_FUNC_EXIT();
}




STATIC int32
sys_acl_kfield_cfg_is_valid(int32 lchip,
                            sys_acl_field_t field_id,
                            sys_acl_keygen_cfg_t *keygen_cfg,
                            sys_acl_kfield_cfg_t *field_cfg,
                            uint16 field_cfg_max_size,
                            uint8 *field_cfg_is_valid)
{
    uint8 idx = 0;
    uint8 field_cfg_chunk_id = 0;
    uint16 bit = 0;
    uint16 start_bit = 0;
    uint16 end_bit = 0;
    uint16 width = 0;
    uint32 *field_bitmap = NULL;
    uint32 field_bitmap1[SYS_ACL_KFIELD_BITMAP_MAX_WORDS] = {0};
    uint32 field_bitmap2[SYS_ACL_KFIELD_BITMAP_MAX_WORDS] = {0};

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(field_cfg, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(field_cfg_is_valid, CTC_E_INVALID_PARAM);

    *field_cfg_is_valid = 0;

    for (idx = 0; idx < keygen_cfg->field_info_count; idx++)
    {
        if (keygen_cfg->field_info_arr[idx].field_id == field_id &&
            keygen_cfg->field_info_arr[idx].partial == TRUE)
        {
            field_bitmap = keygen_cfg->field_info_arr[idx].bitmap;
            break;
        }
    }

    if (field_bitmap == NULL)
    {
        sal_memset(field_bitmap2, 0, sizeof(field_bitmap2));
        for (bit = 0; bit < field_cfg_max_size; bit++)
        {
            CTC_BMP_SET(field_bitmap2, bit);
        }
        field_bitmap = field_bitmap2;
    }

    start_bit = 0;
    end_bit = 0;
    width = 0;
    sal_memset(field_bitmap1, 0, sizeof(field_bitmap1));

    for (field_cfg_chunk_id = 0;  field_cfg_chunk_id < field_cfg->num_chunks;  field_cfg_chunk_id++)
    {
        start_bit += width;
        width = field_cfg->e_params[field_cfg_chunk_id].width;
        end_bit += width;

        for (bit = start_bit; bit < end_bit; bit++)
        {
            CTC_BMP_SET(field_bitmap1, bit);
        }
    }

    *field_cfg_is_valid = TRUE;

    CTC_BMP__ITER(field_bitmap, field_cfg_max_size - 1, bit)
    {
        if (!CTC_BMP_ISSET(field_bitmap1, bit))
        {
            *field_cfg_is_valid = FALSE;
            break;
        }
    }

exit:
    STS_ACL_FUNC_EXIT();
}


STATIC int32
sys_acl_kfield_cfg_info_free(int32 lchip,
                             sys_acl_kfield_cfg_info_t **field_cfg_info)
{
    sys_acl_field_t field_id;

    STS_ACL_FUNC_ENTER(lchip);

    if (field_cfg_info)
    {
        for (field_id = 0; field_id < SYS_ACL_FIELD_COUNT; field_id++)
        {
            if (field_cfg_info[field_id])
            {
                STS_ACL_FREE(field_cfg_info[field_id]->field_cfg_arr);
                STS_ACL_FREE(field_cfg_info[field_id]);
            }
        }
    }

    STS_ACL_FUNC_EXIT();
}

int32
sys_acl_kfield_cfg_info_db_free(int32 lchip,
                  sys_acl_kfield_cfg_info_db_t *field_cfg_info_db)
{
    sys_acl_kfield_cfg_info_t **field_cfg_info = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(field_cfg_info_db, CTC_E_NONE);

    /* Free bus qids sec_cfg memory. */
    field_cfg_info = field_cfg_info_db->field_cfg_info;
    sys_acl_kfield_cfg_info_free(lchip, field_cfg_info);

exit:
    STS_ACL_FUNC_EXIT();
}



//keygen_cfg ����Ч��qid cfg ����keygen_md
STATIC int32
sys_acl_kfield_cfg_info_alloc(int32 lchip,
                              sys_acl_keygen_cfg_t *keygen_cfg,
                              sys_acl_keygen_md_t *keygen_md)
{
    uint8 field_cfg_is_valid = FALSE;
    uint8 field_cfg_count = 0;
    uint8 valid_field_cfg_count = 0;
    uint8 field_cfg_id = 0;
    uint16 idx = 0;
    uint16 field_cfg_max_size = 0;
    uint32 field_cfg_id_bmp = 0;
    sys_acl_field_t field_id;
    sys_acl_kfield_cfg_t *field_cfg = NULL;
    sys_acl_kfield_cfg_t *field_cfg_arr = NULL;
    sys_acl_kfield_cfg_info_t **field_cfg_info1 = NULL;
    sys_acl_kfield_cfg_info_t *field_cfg_info2 = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);

    field_cfg_info1 = keygen_cfg->field_cfg_info_db->field_cfg_info;

    STS_ACL_IF_ERR_EXIT((field_cfg_info1 == NULL) ? CTC_E_INVALID_CONFIG : CTC_E_NONE);

    for (idx = 0; idx < keygen_cfg->field_info_count; idx++)
    {

        field_id =  keygen_cfg->field_info_arr[idx].field_id;

        if (field_cfg_info1[field_id] == NULL)
        {
            continue;
        }

        STS_ACL_IF_ERR_EXIT(
            sys_acl_kfield_cfg_max_size_get(lchip,
                                        keygen_cfg,
                                        field_id,
                                        &field_cfg_max_size));

        valid_field_cfg_count = 0;
        field_cfg_id_bmp = 0;

        for (field_cfg_id = 0;
            field_cfg_id < field_cfg_info1[field_id]->num_field_cfg;
        field_cfg_id++)
        {

            field_cfg = &(field_cfg_info1[field_id]->field_cfg_arr[field_cfg_id]);
            field_cfg_is_valid = FALSE;

            STS_ACL_IF_ERR_EXIT(
            sys_acl_kfield_cfg_is_valid(lchip,
                                           field_id,
                                           keygen_cfg,
                                           field_cfg,
                                           field_cfg_max_size,
                                           &field_cfg_is_valid));

            if (field_cfg_is_valid == TRUE)
            {
                CTC_BMP_SET(&field_cfg_id_bmp, field_cfg_id);
                valid_field_cfg_count++;
            }
        }

        STS_ACL_IF_ERR_EXIT((valid_field_cfg_count == 0) ? CTC_E_INVALID_CONFIG : CTC_E_NONE);

        field_cfg_info2 = NULL;

        SYS_ACL_ALLOC(field_cfg_info2,  sizeof(sys_acl_kfield_cfg_info_t));

        keygen_md->field_cfg_info[field_id] = field_cfg_info2;

        field_cfg_arr = NULL;

        SYS_ACL_ALLOC(field_cfg_arr,
                  valid_field_cfg_count * sizeof(sys_acl_kfield_cfg_t));

        field_cfg_info2->num_field_cfg = valid_field_cfg_count;
        field_cfg_info2->field_cfg_arr = field_cfg_arr;

        field_cfg_count = 0;

        for (field_cfg_id = 0;
            field_cfg_id < field_cfg_info1[field_id]->num_field_cfg;
        field_cfg_id++)
        {

            field_cfg = &(field_cfg_info1[field_id]->field_cfg_arr[field_cfg_id]);

            if (CTC_BMP_ISSET(&field_cfg_id_bmp, field_cfg_id))
            {
                field_cfg =
                &(field_cfg_info1[field_id]->field_cfg_arr[field_cfg_id]);
                sal_memcpy(&(field_cfg_arr[field_cfg_count]),
                           field_cfg, sizeof(sys_acl_kfield_cfg_t));
                field_cfg_count++;
            }
        }
    }

exit:
    if (STS_ACL_FUNC_ERR()) {
        (void)sys_acl_kfield_cfg_info_free(lchip, keygen_md->field_cfg_info);
    }

    STS_ACL_FUNC_EXIT();
}


STATIC int32
sys_acl_kfield_cfg_info_db_alloc(int32 lchip,
                                 sys_acl_keygen_cfg_t *keygen_cfg,
                                 sys_acl_keygen_md_t *keygen_md)
{
    uint8 level = 0;
    uint16 idx = 0;
    sys_acl_field_t field_id;
    sys_acl_kfield_cfg_t *field_cfg_arr = NULL;
    sys_acl_kfield_cfg_info_t *field_cfg_info = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);

    for (level = 0; level < SYS_ACL_KEXT_LEVEL_COUNT; level++)
    {
        keygen_md->field_cfg_info_db[level] = NULL;
    }

    SYS_ACL_ALLOC(keygen_md->field_cfg_info_db[0],
                sizeof(sys_acl_kfield_cfg_info_db_t));

    for (idx = 0; idx < keygen_cfg->field_info_count; idx++)
    {
        field_id = keygen_cfg->field_info_arr[idx].field_id;

        if (keygen_cfg->field_cfg_info_db->field_cfg_info[field_id] == NULL)
        {
            continue;
        }

        SYS_ACL_ALLOC(field_cfg_info,
                    sizeof(sys_acl_kfield_cfg_info_t));
        keygen_md->field_cfg_info_db[0]->field_cfg_info[field_id] = field_cfg_info;

        SYS_ACL_ALLOC(field_cfg_arr,
                    sizeof(sys_acl_kfield_cfg_t));
        field_cfg_info->field_cfg_arr = field_cfg_arr;
        field_cfg_info->num_field_cfg = 1;
        field_cfg_info = NULL;
        field_cfg_arr = NULL;
    }

exit:
    if (STS_ACL_FUNC_ERR())
    {
        (void) sys_acl_kfield_cfg_info_db_free(lchip, keygen_md->field_cfg_info_db[0]);
        STS_ACL_FREE(keygen_md->field_cfg_info_db[0]);
    }
    STS_ACL_FUNC_EXIT();
}

STATIC int32
sys_acl_kfield_cfg_id_array_alloc(int32 lchip,
                                  sys_acl_keygen_cfg_t *keygen_cfg,
                                  sys_acl_keygen_md_t *keygen_md)
{
    uint16 idx = 0;
    sys_acl_field_t field_id;
#if 0
    sys_acl_kfield_cfg_t *field_cfg2 = NULL;

    uint32 sum = 0;
#endif
    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);

    SYS_ACL_ALLOC(keygen_md->field_cfg_id_arr,  sizeof(uint8) * keygen_cfg->field_info_count);

    keygen_md->field_cfg_combinations = 1;

    for (idx = 0; idx < keygen_cfg->field_info_count; idx++)
    {
        field_id = keygen_cfg->field_info_arr[idx].field_id;
        keygen_md->field_cfg_combinations *=  keygen_md->field_cfg_info[field_id]->num_field_cfg;
#if 0
        if (keygen_md->field_cfg_info[field_id]->num_field_cfg == 1)
        {
            field_cfg2 = &(keygen_md->field_cfg_info[field_id]->field_cfg_arr[0]);
            sal_printf("qid :%s,  size:%d\n", ifp_field_str[field_id], field_cfg2->size);
            sum += field_cfg2->size;
        }
#endif
    }

#if 0
    sal_printf("Static key size:%d\n", sum);
    if (sum > keygen_cfg->num_parts*160)
    {
        return CTC_E_INVALID_PARAM;
    }
#endif

exit:
    STS_ACL_FUNC_EXIT();
}



STATIC int32
sys_acl_kext_cfg_alloc(int32 lchip,
                        sys_acl_keygen_cfg_t *keygen_cfg,
                        sys_acl_keygen_md_t *keygen_md)
{
    int32 alloc_sz = 0;
    int32 idx = 0;
    int32 level = 0;
    int32 num_sec = 0;
    sys_acl_kext_sec_t ext_sel = 0;
    sys_acl_kext_sec_cfg_t *org_ext_secs = NULL;
    sys_acl_kext_cfg_db_t *orig_ext_info = NULL;
    sys_acl_kext_cfg_db_t **ext_info = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);

    ext_info = &(keygen_md->ext_cfg_db);
    orig_ext_info = keygen_cfg->ext_cfg_db;

    if (NULL == orig_ext_info)
    {
        STS_ACL_IF_ERR_EXIT(CTC_E_INVALID_CONFIG);
    }

    SYS_ACL_ALLOC(*ext_info, sizeof(sys_acl_kext_cfg_db_t));
    (*ext_info)->mode = keygen_cfg->ext_cfg_db->mode;
    keygen_md->num_ext_levels = orig_ext_info->num_ext_levels - 1;

    for (level = 1; level < orig_ext_info->num_ext_levels; level++)
    {

        alloc_sz = orig_ext_info->conf_size[level];

        if (0 == alloc_sz)
        {
            STS_ACL_IF_ERR_EXIT(CTC_E_INVALID_CONFIG);
        }

        SYS_ACL_ALLOC((*ext_info)->ext_cfg[level],
                    (alloc_sz * sizeof(sys_acl_kext_cfg_t)));
        sal_memcpy((*ext_info)->ext_cfg[level], orig_ext_info->ext_cfg[level],
                   alloc_sz * sizeof(sys_acl_kext_cfg_t));
        (*ext_info)->conf_size[level] = orig_ext_info->conf_size[level];
    }

    if (orig_ext_info->num_sec > 0)
    {
        (*ext_info)->num_sec = orig_ext_info->num_sec;
        num_sec = (*ext_info)->num_sec;
        for (ext_sel = SYS_ACL_KEXT_SECTION_L1E32; ext_sel < SYS_ACL_KEXT_SECTION_COUNT; ext_sel++)
        {
            org_ext_secs = orig_ext_info->sec_cfg[ext_sel];

            if (NULL != org_ext_secs)
            {
                SYS_ACL_ALLOC((*ext_info)->sec_cfg[ext_sel],
                            sizeof(sys_acl_kext_sec_cfg_t));
                sal_memcpy((*ext_info)->sec_cfg[ext_sel], org_ext_secs,
                           sizeof(sys_acl_kext_sec_cfg_t));
                num_sec--;
            }
        }
    }


    STS_ACL_FUNC_EXIT();
exit:
    if (ext_info != NULL)
    {
        if (*ext_info != NULL)
        {
            for (idx = 1; idx < SYS_ACL_KEXT_LEVEL_COUNT; idx++)
            {
                STS_ACL_FREE((*ext_info)->ext_cfg[idx]);
            }
            for (idx = 0; idx < SYS_ACL_KEXT_SECTION_COUNT; idx++)
            {
                STS_ACL_FREE((*ext_info)->sec_cfg[idx]);
            }
            STS_ACL_FREE(*ext_info);
        }
    }
    STS_ACL_FUNC_EXIT();
}


STATIC int32
sys_acl_kext_secs_get(int32 lchip,
                           sys_acl_keygen_cfg_t *keygen_cfg,
                           sys_acl_keygen_md_t *keygen_md)
{
    uint8 part = 0;
    uint8 level = 0;
    uint16 ext_idx = 0;
    sys_acl_kext_cfg_t *ext_cfg = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);

    for (level = 1; level <= keygen_md->num_ext_levels; level++)
    {
        for (ext_idx = 0;  ext_idx < keygen_md->ext_cfg_db->conf_size[level]; ext_idx++)
        {
            ext_cfg =  keygen_md->ext_cfg_db->ext_cfg[level] + ext_idx;

            part = SYS_ACL_KEXT_ID_PART_GET(ext_cfg->ext_id);

            keygen_md->sections[part][level - 1][ext_cfg->in_sec] =  ext_cfg->in_sec;
        }
    }

exit:
    STS_ACL_FUNC_EXIT();
}



STATIC int32
sys_acl_kext_sec_gran_info_init(int32 lchip,
                              sys_acl_keygen_md_t *keygen_md)
{
    uint8 idx = 0;
    uint8 part = 0;
    uint8 gran = 0;
    uint8 level = 0;
    uint8 found = 0;
    uint16 size = 0;
    uint8 *gran_info_count = 0;
    uint16 ext_idx = 0;
    sys_acl_kext_sec_t in_sec;
    sys_acl_kext_sec_t out_sec;
    sys_acl_kext_cfg_t *ext_cfg = NULL;
    sys_acl_kext_sec_gran_t *gran_info = NULL;
    sys_acl_kext_sec_gran_info_t *section_gran_info = NULL;

    STS_ACL_FUNC_ENTER(lchip);
    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);

    size = sizeof(sys_acl_kext_sec_gran_info_t) * SYS_ACL_KEXT_SECTION_COUNT;
    sal_memset(keygen_md->section_gran_info, 0, size);


    for (level = 1; level < (keygen_md->num_ext_levels + 1); level++)
    {
        for (ext_idx = 0;  ext_idx < keygen_md->ext_cfg_db->conf_size[level];  ext_idx++)
        {
            ext_cfg = keygen_md->ext_cfg_db->ext_cfg[level] + ext_idx;
            part = SYS_ACL_KEXT_ID_PART_GET(ext_cfg->ext_id);
            gran = SYS_ACL_KEXT_ID_GRAN_GET(ext_cfg->ext_id);

            ret = sys_acl_kext_validate(lchip, part, keygen_md, ext_cfg);
            if (STS_ACL_FUNC_VAL_IS(CTC_E_INVALID_CONFIG)) {
               continue;
            }

            STS_ACL_IF_ERR_EXIT(ret);
            in_sec = ext_cfg->in_sec;
            out_sec = ext_cfg->out_sec;
            section_gran_info = &(keygen_md->section_gran_info[in_sec]);

            {
                gran_info = &section_gran_info->out_gran_info[0];
                gran_info_count = &section_gran_info->out_gran_info_count;
            }

            found = FALSE;

            for (idx = 0; idx < *gran_info_count; idx++)
            {
                if (gran_info[idx].gran == gran)
                {
                    found = TRUE;
                    gran_info[idx].num_extractors++;
                    break;
                }
            }

            if (found == FALSE)
            {
                gran_info[*gran_info_count].gran = gran;
                gran_info[*gran_info_count].num_extractors++;
                (*gran_info_count)++;
            }

           found = FALSE;
           section_gran_info = &(keygen_md->section_gran_info[out_sec]);
           gran_info = &section_gran_info->in_gran_info[0];
           gran_info_count = &section_gran_info->in_gran_info_count;

           for (idx = 0; idx < *gran_info_count; idx++)
           {
               if (gran_info[idx].gran == gran)
               {
                   found = TRUE;
                   gran_info[idx].num_extractors++;
                   break;
               }
           }

           if (found == FALSE)
           {
               gran_info[*gran_info_count].gran = gran;
               gran_info[*gran_info_count].num_extractors++;
               (*gran_info_count)++;
           }

        }
    }

    STS_ACL_RETURN_VAL_EXIT(CTC_E_NONE);

exit:
    STS_ACL_FUNC_EXIT();
}


STATIC int32
sys_acl_kext_codes_init(int32 lchip, sys_acl_kext_sel_t *ext_codes)
{
    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(ext_codes, CTC_E_INVALID_PARAM);

    sal_memset(ext_codes, SYS_ACL_KEXT_SELCODE_DONT_CARE, sizeof(sys_acl_kext_sel_t));

exit:
    STS_ACL_FUNC_EXIT();
}


STATIC int32
sys_acl_keygen_md_alloc(int32 lchip,
                   sys_acl_keygen_cfg_t *keygen_cfg,
                   sys_acl_keygen_md_t **keygen_md)
{
    uint8 part = 0;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);

    SYS_ACL_ALLOC(*keygen_md, sizeof(sys_acl_keygen_md_t));

    STS_ACL_IF_ERR_EXIT(sys_acl_kfield_cfg_info_alloc(lchip, keygen_cfg, *keygen_md));

    STS_ACL_IF_ERR_EXIT(sys_acl_kfield_cfg_info_db_alloc(lchip, keygen_cfg, *keygen_md));

    STS_ACL_IF_ERR_EXIT(sys_acl_kext_cfg_alloc(lchip, keygen_cfg, *keygen_md));

    STS_ACL_IF_ERR_EXIT(sys_acl_kfield_cfg_id_array_alloc(lchip, keygen_cfg, *keygen_md));

    STS_ACL_IF_ERR_EXIT(sys_acl_kext_secs_get(lchip, keygen_cfg, *keygen_md));

    STS_ACL_IF_ERR_EXIT(sys_acl_kext_sec_gran_info_init(lchip, *keygen_md));

    for (part = 0; part < keygen_cfg->num_parts; part++)
    {
        STS_ACL_IF_ERR_EXIT(
        sys_acl_kext_codes_init(lchip, &((*keygen_md)->ext_codes[part])));
    }

exit:
    STS_ACL_FUNC_EXIT();
}


STATIC int32
sys_acl_kext_finfo_list_init(int32 lchip)
{
    uint16 idx = 0;
    
    MALLOC_ZERO(MEM_ACL_MODULE, p_finfo_pool[lchip], sizeof(sys_acl_kext_finfo_t)*SYS_ACL_KEXT_FINFO_COUNT);
    if (NULL == p_finfo_pool[lchip])
    {
        return CTC_E_NO_MEMORY;
    }

    for (idx = 0; idx < (SYS_ACL_KEXT_FINFO_COUNT - 1); idx++)
    {
        p_finfo_pool[lchip][idx].next = &(p_finfo_pool[lchip][idx + 1]);
    }

    p_finfo_pool[lchip][SYS_ACL_KEXT_FINFO_COUNT - 1].next = NULL;
    finfo_free_list[lchip] = p_finfo_pool[lchip];
    finfo_free_count = 1024;
    finfo_used_count = 0;
    
    return CTC_E_NONE;
}

extern char *ifp_field_str[];

STATIC int32
sys_acl_kext_fs_get_first(int32 lchip,
                               sys_acl_keygen_cfg_t *keygen_cfg,
                               sys_acl_keygen_md_t *keygen_md,
                               uint16* p_key_req_bits)
{
    int32 bit_count = 0;
    uint8 idx = 0;
    uint8 f_idx = 0;
    uint8 i = 0, j = 0;
    uint8 field_count = 0;
    uint8 finfo_idx = 0;
    uint8 f_width = 0;
    uint8 sec_val = 0;
    uint8 found = FALSE;
    uint8 field_cfg_id = 0;
    uint8 q_bit = 0;
    uint8 f_bit = 0;
    uint16 f_offset = 0;
    uint16 finfo_size = 0;
    uint16 ctrl_sel_val = 0;
    uint16 field_offset = 0;
    uint16 field_width = 0;
    uint32 field_flags = 0;
    uint16 sum = 0;
    sys_acl_kext_sec_t section;
    sys_acl_kext_ctrl_sel_t ctrl_sel;
    sys_acl_kext_finfo_t *finfo = NULL;
    sys_acl_kext_finfo_t temp_finfo;
    sys_acl_field_t field_id = SYS_ACL_FIELD_COUNT;
    sys_acl_kfield_cfg_t *field_cfg = NULL;
    sys_acl_kfield_cfg_info_t *field_cfg_info = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);

    finfo_size = sizeof(sys_acl_kext_finfo_t) * SYS_ACL_KEXT_FIELDS_MAX;
    sal_memset(keygen_md->finfo, 0, finfo_size);

    for (idx = 0; idx < keygen_cfg->field_info_count; idx++)
    {

        field_cfg_id = keygen_md->field_cfg_id_arr[idx];
        field_id = keygen_cfg->field_info_arr[idx].field_id;
        field_flags = keygen_cfg->field_info_arr[idx].flags;
        field_cfg_info = keygen_md->field_cfg_info[field_id];
        field_cfg = &(field_cfg_info->field_cfg_arr[field_cfg_id]);

        if (CTC_BMP_ISSET(field_cfg->field_flags.w, SYS_ACL_KFIELD_FLAGS_PMUX))
        {
            continue;
        }

        field_offset = 0;

        for (f_idx = 0; f_idx < field_cfg->num_chunks; f_idx++)
        {
            section = field_cfg->e_params[f_idx].section;
            sec_val = field_cfg->e_params[f_idx].sec_val;
            ctrl_sel = field_cfg->pri_ctrl_sel;
            ctrl_sel_val = field_cfg->pri_ctrl_sel_val;

            if (keygen_cfg->field_info_arr[idx].partial == TRUE)
            {
                field_width = field_cfg->e_params[f_idx].width;

                bit_count = 0;

                CTC_BMP_COUNT_RANGE(keygen_cfg->field_info_arr[idx].bitmap,
                                    bit_count, field_offset, field_width);

                field_offset += field_cfg->e_params[f_idx].width;

                if (bit_count == 0)
                {
                    continue;
                }
            }

            for (finfo_idx = 0; finfo_idx < SYS_ACL_KEXT_FIELDS_MAX; finfo_idx++)
            {
                finfo = &(keygen_md->finfo[finfo_idx]);

                if ((finfo->section == section &&
                    finfo->sec_val == sec_val &&
                finfo->pri_ctrl_sel == ctrl_sel &&
                finfo->pri_ctrl_sel_val == ctrl_sel_val &&
                finfo->fixed == 0))
                {
                    found = TRUE;
                }

                /* Ignore 'found' if this flag is set */
                if (field_flags & SYS_ACL_KFIELD_F_USE_FINFO_NEW)
                {
                    found = FALSE;
                }

                if ((found == TRUE) || (finfo->section == SYS_ACL_KEXT_SECTION_DISABLE))
                {
                    break;
                }

                continue;
            }

            if (found == FALSE)
            {
                finfo->size = field_cfg->e_params[f_idx].size;
                finfo->section = section;
                finfo->sec_val = sec_val;
                finfo->pri_ctrl_sel = ctrl_sel;
                finfo->pri_ctrl_sel_val = ctrl_sel_val;

                if (field_id == SYS_ACL_FIELD_LT_ID)
                {
                    finfo->part = 0;
                    finfo->fixed = 1;
                    finfo->qaul_id = SYS_ACL_FIELD_LT_ID;
                }
                else if (field_id == SYS_ACL_FIELD_LT_ID1)
                {
                    finfo->part = 1;
                    finfo->fixed = 1;
                    finfo->qaul_id = SYS_ACL_FIELD_LT_ID1;
                }
                else if (field_id == SYS_ACL_FIELD_LT_ID2)
                {
                    finfo->part = 2;
                    finfo->fixed = 1;
                    finfo->qaul_id = SYS_ACL_FIELD_LT_ID2;
                }
                else
                {
                    finfo->part = -1;
                }

                finfo->ext_bmp[0] = 0;
                finfo->l0_section = section;
                finfo->l0_sec_val = sec_val;
                finfo->l0_field_offset = 0;
                field_count++;
            }

            f_offset = (field_cfg->e_params[f_idx].offset % field_cfg->e_params[f_idx].size);
            f_width = field_cfg->e_params[f_idx].width;

            if (keygen_cfg->field_info_arr[idx].partial == TRUE)
            {
                q_bit = field_offset - f_width;

                for (f_bit = f_offset;
                    f_bit < (f_offset + f_width);
                f_bit++)
                {
                    if (CTC_BMP_ISSET(
                        keygen_cfg->field_info_arr[idx].bitmap, q_bit))
                    {
                        CTC_BMP_SET(finfo->req_bmp, f_bit);
                    }
                    q_bit++;
                }
            }
            else
            {
                CTC_BMP_SET_RANGE(finfo->req_bmp, (int32)f_offset, (int32)f_width);
            }
            found = FALSE;
        }
    }

    for (i = 0; i < field_count; i++)
    {
        int32 bit_cnt = 0;

        CTC_BMP_COUNT_RANGE(keygen_md->finfo[i].req_bmp, bit_cnt,  0, 32);
        /*sal_printf("finfo[%d].req_bmp:0x%x, bit_cnt:%d\n", i, keygen_md->finfo[i].req_bmp[0], bit_cnt);*/

        /*
        for (j = 0; j < keygen_md->finfo[i].cnt; j++)
        {
            sal_printf("qid %d %s\n", keygen_md->finfo[i].qid[j], ifp_field_str[ keygen_md->finfo[i].qid[j]]);
        }
        //*/

        sum += bit_cnt;
    }

    SYS_ACL_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Requst BitCnt:%d\n", sum);
    if (sum > keygen_cfg->num_parts*160)
    {
        SYS_ACL_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Requst BitCnt:%d than %d\n", sum, keygen_cfg->num_parts*160);
        return CTC_E_INVALID_CONFIG;
    }


    /* Sort the finfo List from large to little by bit width */
    for (i = 0; i < field_count; i++)
    {
        for (j = (i + 1); j < field_count; j++)
        {
            if (keygen_md->finfo[j].size > keygen_md->finfo[i].size || keygen_md->finfo[j].fixed)
            {
                sal_memcpy(&temp_finfo, &keygen_md->finfo[i],
                           sizeof(sys_acl_kext_finfo_t));
                sal_memcpy(&keygen_md->finfo[i], &keygen_md->finfo[j],
                           sizeof(sys_acl_kext_finfo_t));
                sal_memcpy(&keygen_md->finfo[j], &temp_finfo,
                           sizeof(sys_acl_kext_finfo_t));
            }
        }
    }

   /*move the field with ctl_sel before others if field width is same*/
    j = 0;
    field_width = keygen_md->finfo[0].size;
    for (i = 0; i < field_count; i++)
    {
        if (field_width != keygen_md->finfo[i].size)
        {
            field_width = keygen_md->finfo[i].size;
            j = i;
        }

        if (keygen_md->finfo[i].pri_ctrl_sel !=  SYS_ACL_KEXT_CTRL_SEL_DISABLE)
        {
            if (j != i)
            {
                sal_memcpy(&temp_finfo, &keygen_md->finfo[j],
                           sizeof(sys_acl_kext_finfo_t));
                sal_memcpy(&keygen_md->finfo[j], &keygen_md->finfo[i],
                           sizeof(sys_acl_kext_finfo_t));
                sal_memcpy(&keygen_md->finfo[i], &temp_finfo,
                           sizeof(sys_acl_kext_finfo_t));
            }
            j++;
        }
    }

    *p_key_req_bits = sum;

exit:
    STS_ACL_FUNC_EXIT();
}



STATIC int32
sys_acl_kext_code_part_get(int32 lchip,
                              sys_acl_keygen_md_t *keygen_md,
                              sys_acl_kext_ctrl_sel_t ctrl_sel,
                              uint8 ctrl_sel_val,
                              int8 *part)
{
    uint8 idx = 0;
    sys_acl_kext_finfo_t *finfo = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(part, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);

    *part = -1;
    for (idx = 0; idx < SYS_ACL_KEXT_FIELDS_MAX; idx++) {
       finfo = &(keygen_md->finfo[idx]);
       if (finfo->section == SYS_ACL_KEXT_SECTION_DISABLE) {
          break;
       }
       if (finfo->part == -1) {
           continue;
       }
       if (finfo->pri_ctrl_sel == ctrl_sel &&
           finfo->pri_ctrl_sel_val == ctrl_sel_val) {
           *part = finfo->part;
           break;
       }
    }

exit:
    STS_ACL_FUNC_EXIT();
}

STATIC int32
sys_acl_kext_part_get(int32 lchip,
                         sys_acl_keygen_cfg_t *keygen_cfg,
                         sys_acl_keygen_md_t *keygen_md,
                         sys_acl_kext_finfo_t *finfo)
{
    int8 part = -1;
    uint8 idx = 0;
    uint8 found_untried_part = FALSE;
    uint16 bits_extracted = 0;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(finfo, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);

    if (finfo->pri_ctrl_sel != SYS_ACL_KEXT_CTRL_SEL_DISABLE)
    {
        STS_ACL_IF_ERR_EXIT(
        sys_acl_kext_code_part_get(lchip, keygen_md, finfo->pri_ctrl_sel,
                                         finfo->pri_ctrl_sel_val, &part));
    }

    if (part != -1 && !(keygen_md->tried_part_bmp[0] & (1 << part)))
    {
        keygen_md->tried_part_bmp[0] |= (1 << part);
        finfo->part = part;
        STS_ACL_RETURN_VAL_EXIT(CTC_E_NONE);
    }

    for (idx = 0; idx < keygen_cfg->num_parts; idx++)
    {
        if (keygen_md->tried_part_bmp[0] & (1 << idx))
        {
            continue;
        }
        if (!found_untried_part)
        {
            found_untried_part = TRUE;
            part = idx;
            bits_extracted = keygen_md->bits_extracted[idx][0];
            continue;
        }
        if (bits_extracted > keygen_md->bits_extracted[idx][0])
        {
            part = idx;
            bits_extracted = keygen_md->bits_extracted[idx][0];
        }
    }

    if (part != -1)
    {
        keygen_md->tried_part_bmp[0] |= (1 << part);
        finfo->part = part;
    }
    else
    {
        STS_ACL_IF_ERR_EXIT(CTC_E_INVALID_CONFIG);
    }
exit:
    STS_ACL_FUNC_EXIT();
}


STATIC int32
sys_acl_kext_finfo_add(int32 lchip,
                        uint8 part,
                        sys_acl_keygen_md_t *keygen_md)
{
    uint8 idx = 0;
    sys_acl_kext_sec_t section;
    sys_acl_kext_finfo_t *temp_finfo1 = NULL;
    sys_acl_kext_finfo_t *temp_finfo2 = NULL;
    sys_acl_kext_finfo_t *temp_finfo3 = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);

    for (idx = 0; idx < SYS_ACL_KEXT_FIELDS_MAX; idx++)
    {
        temp_finfo1 = &(keygen_md->finfo[idx]);
        section = temp_finfo1->section;

        if (section == SYS_ACL_KEXT_SECTION_DISABLE)
        {
            break;
        }
        if (temp_finfo1->part != part)
        {
            continue;
        }

        temp_finfo2 = finfo_free_list[lchip];
        STS_ACL_IF_ERR_EXIT((temp_finfo2 == NULL) ? CTC_E_INVALID_CONFIG : CTC_E_NONE);
        finfo_free_list[lchip] = finfo_free_list[lchip]->next;
        DUMP_FINFO_COUNT(0);
        sal_memcpy(temp_finfo2, temp_finfo1, sizeof(sys_acl_kext_finfo_t));
        temp_finfo2->next = NULL;

        if (keygen_md->ext_finfo_db[part][0].finfo[section] == NULL)
        {
            keygen_md->ext_finfo_db[part][0].finfo[section] = temp_finfo2;
        }
        else
        {
            temp_finfo3 = keygen_md->ext_finfo_db[part][0].finfo[section];

            while (temp_finfo3->next != NULL)
            {
                temp_finfo3 = temp_finfo3->next;
            }

            temp_finfo3->next = temp_finfo2;
        }
    }

exit:
    STS_ACL_FUNC_EXIT();
}



STATIC int32
sys_acl_kext_codes_validate(int32 lchip,
                               uint8 part,
                               sys_acl_keygen_cfg_t *keygen_cfg,
                               sys_acl_keygen_md_t *keygen_md)
{
    uint8 idx = 0;
    sys_acl_kext_finfo_t *finfo = NULL;
    sys_acl_kext_ctrl_sel_info_t *keygen_ext_code = NULL;
    sys_acl_kext_sel_t *grp_ext_code = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);

    STS_ACL_IF_ERR_EXIT(
    sys_acl_kext_codes_init(lchip, &(keygen_md->ext_codes[part])));

    for (idx = 0; idx < keygen_cfg->ext_ctrl_sel_info_count; idx++)
    {
        keygen_ext_code = &(keygen_cfg->ext_ctrl_sel_info[idx]);
        grp_ext_code = &(keygen_md->ext_codes[keygen_ext_code->part]);

        if ( idx >= SYS_ACL_KEXT_CTRL_SEL_START &&
            idx < SYS_ACL_KEXT_CTRL_SEL_MAX &&
        keygen_ext_code->ctrl_sel == idx)
        {
            grp_ext_code->sel_ctl[idx] =  keygen_ext_code->ctrl_sel_val;
        }
        else
        {
            continue;
        }
    }

    for (idx = 0; idx < SYS_ACL_KEXT_FIELDS_MAX; idx++)
    {
        finfo = &(keygen_md->finfo[idx]);

        if (finfo->section == SYS_ACL_KEXT_SECTION_DISABLE)
        {
            break;
        }

        if (finfo->part != part)
        {
            continue;
        }

        if (finfo->pri_ctrl_sel == SYS_ACL_KEXT_CTRL_SEL_DISABLE)
        {
            continue;
        }

        if (finfo->pri_ctrl_sel >= SYS_ACL_KEXT_CTRL_SEL_MAX)
        {
            STS_ACL_IF_ERR_EXIT(CTC_E_INVALID_CONFIG);
        }

        if (keygen_md->ext_codes[part].sel_ctl[finfo->pri_ctrl_sel] == SYS_ACL_KEXT_SELCODE_DONT_CARE)
        {
            keygen_md->ext_codes[part].sel_ctl[finfo->pri_ctrl_sel] =  finfo->pri_ctrl_sel_val;
        }
        else if (keygen_md->ext_codes[part].sel_ctl[finfo->pri_ctrl_sel] != finfo->pri_ctrl_sel_val)
        {
            STS_ACL_IF_ERR_EXIT(CTC_E_NO_RESOURCE);
        }

    }

exit:
    STS_ACL_FUNC_EXIT();
}



STATIC int32
sys_acl_kext_sec_validate(int32 lchip,
                                 sys_acl_kext_cfg_t *ext_cfg,
                                 sys_acl_kext_finfo_t *finfo,
                                 sys_acl_keygen_md_t *keygen_md)
{
    uint8 gran = 0;
    uint8 level = 0;
    uint16 req_bits = 0;
    uint16 fill_bits = 0, parent_fill_bits = 0;
    uint16 drain_bits = 0, parent_drain_bits = 0;
    sys_acl_kext_sec_t out_sec;
    sys_acl_kext_sec_t parent_sec;

    STS_ACL_FUNC_ENTER(lchip);
    STS_ACL_NULL_CHECK(ext_cfg, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(finfo, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);

    gran = SYS_ACL_KEXT_ID_GRAN_GET(ext_cfg->ext_id);
    level = SYS_ACL_KEXT_ID_LEVEL_GET(ext_cfg->ext_id);
    req_bits = (level == 2) ? finfo->req_bit_count : gran;

    out_sec = ext_cfg->out_sec;
    fill_bits = keygen_md->ext_cfg_db->sec_cfg[out_sec]->fill_bits;
    drain_bits = keygen_md->ext_cfg_db->sec_cfg[out_sec]->drain_bits;

    parent_sec = keygen_md->ext_cfg_db->sec_cfg[out_sec]->parent_sec;
    parent_fill_bits = keygen_md->ext_cfg_db->sec_cfg[parent_sec]->fill_bits;
    parent_drain_bits = keygen_md->ext_cfg_db->sec_cfg[parent_sec]->drain_bits;

    if (((fill_bits + req_bits) > drain_bits) ||
        ((parent_fill_bits + req_bits) > parent_drain_bits))
    {
        STS_ACL_RETURN_VAL_EXIT(CTC_E_NO_RESOURCE);
    }

exit:
    STS_ACL_FUNC_EXIT();
}


STATIC int32
sys_acl_kext_alloc_3(int32 lchip,
                      uint8 part,
                      uint8 level,
                      sys_acl_kext_sec_t section,
                      sys_acl_keygen_cfg_t *keygen_cfg,
                      sys_acl_keygen_md_t *keygen_md)
{
    int32 g = 0, p = 0, l = 0;
    uint16 ext_idx = 0;
    uint16 ext_start = 0;
    sys_acl_kext_sec_t out_sec;
    sys_acl_kext_sec_t parent_sec;
    sys_acl_kext_cfg_t *ext_cfg = NULL;
    sys_acl_kext_finfo_t *finfo = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);

    /* Assign extractors to each field of the section. */
    finfo = keygen_md->ext_finfo_db[part][level].finfo[section];
    while (finfo != NULL)
    {
        for (ext_idx = ext_start;
            ext_idx < keygen_md->ext_cfg_db->conf_size[level + 1];
            ext_idx++)
        {
            ext_cfg =  keygen_md->ext_cfg_db->ext_cfg[level + 1] + ext_idx;
            g = SYS_ACL_KEXT_ID_GRAN_GET(ext_cfg->ext_id);
            p = SYS_ACL_KEXT_ID_PART_GET(ext_cfg->ext_id);
            l = SYS_ACL_KEXT_ID_LEVEL_GET(ext_cfg->ext_id);

            if ((p != part) ||
                (l != (level + 1)) ||
            (g != finfo->size) ||
            (section != ext_cfg->in_sec))
            {
                continue;
            }

            if (ext_cfg->in_use == TRUE ) 
            {
                sys_acl_kext_finfo_t * finfo1 = (sys_acl_kext_finfo_t *)ext_cfg->finfo;
                if(finfo->half_flag + finfo1->half_flag == SYS_ACL_KEXT_F_HALF_TOTAL && finfo->sec_val == finfo1->sec_val)
                {   /* f half low node and high node use the same ext_cfg */
                    finfo->extracted = TRUE;
                    finfo->ext_cfg = ext_cfg;
                    ext_cfg->finfo1 = finfo;    /* for f half-high node */
                    ext_start = 0;
                    break;
                }
                continue;
            }

             STS_ACL_IF_ERR_EXIT(ret);
             if (CTC_FLAG_ISSET(keygen_md->ext_cfg_db->sec_cfg[ext_cfg->in_sec]->flags, SYS_ACL_KEXT_SEC_PASSTHRU))
             {
                 ret = sys_acl_kext_sec_validate(lchip,
                                                                ext_cfg, finfo, keygen_md);

                 if (STS_ACL_FUNC_VAL_IS(CTC_E_NO_RESOURCE))
                 {
                     continue;
                 }
             }

            out_sec = ext_cfg->out_sec;
            parent_sec = keygen_md->ext_cfg_db->sec_cfg[out_sec]->parent_sec;

            if (CTC_FLAG_ISSET(keygen_md->ext_cfg_db->sec_cfg[ext_cfg->in_sec]->flags, SYS_ACL_KEXT_SEC_PASSTHRU) || l == 2)
            {
                keygen_md->ext_cfg_db->sec_cfg[out_sec]->fill_bits += finfo->req_bit_count;

                if (parent_sec != out_sec)
                {
                    keygen_md->ext_cfg_db->sec_cfg[parent_sec]->fill_bits += finfo->req_bit_count;
                }
            }
            else
            {
                keygen_md->ext_cfg_db->sec_cfg[out_sec]->fill_bits += g;

                if (parent_sec != out_sec)
                {
                    keygen_md->ext_cfg_db->sec_cfg[parent_sec]->fill_bits += g;
                }
            }

            ext_cfg->finfo = finfo;
            ext_cfg->in_use = TRUE;
            finfo->extracted = TRUE;
            finfo->ext_cfg = ext_cfg;
            
            if(finfo->half_flag == SYS_ACL_KEXT_F_HALF_LOW)
            {   /* next node must be anthoer half, if exist, then use the same ext_cfg */
                ext_start = ext_idx;
            }
            break;
        }
        SYS_ACL_DBG_PRINT("[alloc_3] part:%d, level:%d, g:%d, half %d, reqBitCnt:%d, sec_val:%d \n", part, l, g, finfo->half_flag, finfo->req_bit_count, finfo->sec_val);
        STS_ACL_IF_ERR_EXIT((finfo->extracted == FALSE) ? CTC_E_NO_RESOURCE : CTC_E_NONE);
        finfo = finfo->next;
    }


    STS_ACL_RETURN_VAL_EXIT(CTC_E_NONE);

exit:
    STS_ACL_FUNC_EXIT();
}


STATIC int32
sys_acl_kext_alloc_2(int32 lchip,
                      uint8 part,
                      uint8 level,
                      sys_acl_keygen_cfg_t *keygen_cfg,
                      sys_acl_keygen_md_t *keygen_md)
{
    uint8 sec_idx = 0;
    sys_acl_kext_sec_t section;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);

    for (sec_idx = 0; sec_idx < SYS_ACL_KEXT_SECTION_COUNT; sec_idx++)
    {
        section = keygen_md->sections[part][level][sec_idx];

        if (section == SYS_ACL_KEXT_SECTION_DISABLE)
        {
            continue;
        }

        STS_ACL_IF_ERR_EXIT(sys_acl_kext_alloc_3(lchip, part, level,
                                 section, keygen_cfg, keygen_md));
    }

exit:
    STS_ACL_FUNC_EXIT();
}

/*
 * Notes:
 * Default behavior of this function is to allow any granularity
 * if finfo flags are not set
 */
STATIC int32
sys_acl_keygen_finfo_flags_verify(int32 lchip,
                          uint8 level,
                          uint8 gran,
                          sys_acl_kext_finfo_t *finfo)
{
    uint8 g_idx = 0;
    uint8 index = 0;
    uint8 found = TRUE;
    uint8 exp_level = 0;
    uint8 exp_gran[SYS_ACL_KEXT_GRAN_SIZE] = {0};

    if (finfo->flags & SYS_ACL_KEXT_F_USE_L2_GRAN16)
    {
        exp_level = 1;
        exp_gran[index] = 16;
        index++;
    }

    if (finfo->flags & SYS_ACL_KEXT_F_USE_L2_GRAN8)
    {
        exp_level = 1;
        exp_gran[index] = 8;
        index++;
    }

    if ((exp_level == level) && (index != 0))
    {
        found = FALSE;
        for (g_idx = 0; g_idx < index; g_idx++)
        {
            if (exp_gran[g_idx] == gran)
            {
                found = TRUE;
                break;
            }
        }
    }

    return found;
}


STATIC int32
sys_acl_kext_finfo_node_add(int32 lchip,
                  uint8 order_type,
                  sys_acl_kext_finfo_t *in_node,
                  sys_acl_kext_finfo_t **head_node)
{
    sys_acl_kext_finfo_t *temp_node1 = NULL;
    sys_acl_kext_finfo_t *temp_node2 = NULL;


    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(in_node, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(head_node, CTC_E_INVALID_PARAM);

    in_node->next = NULL;

    if (*head_node == NULL)
    {
        *head_node = in_node;
        STS_ACL_RETURN_VAL_EXIT(CTC_E_NONE);
    }

    if (order_type == ORDER_TYPE_ASCENDING)
    {
        STS_ACL_RETURN_VAL_EXIT(CTC_E_INVALID_CONFIG);
    }
    else if(order_type == ORDER_TYPE_DESCENDING)
    {
        temp_node1 = temp_node2 = *head_node;
        while (temp_node1 != NULL)
        {
            if (temp_node1->req_bit_count < in_node->req_bit_count)
            {
                in_node->next = temp_node1;

                if (temp_node1 == temp_node2)
                {
                    *head_node = in_node;
                    break;
                }

                temp_node2->next = in_node;
                break;
            }

            temp_node2 = temp_node1;
            temp_node1 = temp_node1->next;
        }

        if (temp_node1 == NULL)
        {
            in_node->next = NULL;
            temp_node2->next = in_node;
        }
    }
    else if (order_type == ORDER_TYPE_END_OF_LIST)
    {
        temp_node1 = *head_node;

        while (temp_node1->next != NULL)
        {
            temp_node1 = temp_node1->next;
        }

        temp_node1->next = in_node;
    }
    else if (order_type == ORDER_TYPE_START_OF_LIST)
    {
        in_node->next = *head_node;
        *head_node = in_node;
    }
    else
    {
        STS_ACL_IF_ERR_EXIT(CTC_E_INVALID_CONFIG);
    }

exit:
    STS_ACL_FUNC_EXIT();
}


STATIC int32
sys_acl_kext_fields_create(int32 lchip,
                            uint8 part,
                            uint8 level,
                            sys_acl_kext_sec_t section,
                            uint8 gran,
                            uint8 num_ext,
                            sys_acl_keygen_cfg_t *keygen_cfg,
                            sys_acl_keygen_md_t *keygen_md)
{
    int32 count = 0;
    int32 count2 = 0;
    int32 count3 = 0;
    uint8 idx = 0;
    uint8 chunk = 0;
    uint8 num_chunks = 0;
    uint8 order_type = 0;
    uint8 flags_check = FALSE;
    uint8 half = 0;
    uint16 ext_idx = 0;
    uint16 ext_offset = 0;
    sys_acl_kext_cfg_t *ext_cfg = NULL;
    sys_acl_kext_sec_cfg_t *sec_cfg = NULL;
    sys_acl_kext_finfo_t *temp_finfo1 = NULL;
    sys_acl_kext_finfo_t *temp_finfo2 = NULL;
    sys_acl_kext_finfo_t *temp_finfo3 = NULL;
    sys_acl_kext_finfo_t *temp_finfo4 = NULL;
    sys_acl_kext_finfo_t *temp_finfo_list = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);

    for (ext_idx = 0;  ext_idx < keygen_md->ext_cfg_db->conf_size[level];  ext_idx++)
    {
        ext_cfg =  keygen_md->ext_cfg_db->ext_cfg[level] + ext_idx;

        if (ext_cfg->out_sec != section || ext_cfg->in_use == FALSE)
        {
            continue;
        }

        temp_finfo1 = ext_cfg->finfo;

        if (temp_finfo1 == NULL)
        {
            if (CTC_BMP_ISSET(ext_cfg->ext_attrs.w,
                              SYS_ACL_KEXT_ATTR_NOT_WITH_QSET_UPDATE))
            {
                continue;
            }
            else
            {
                STS_ACL_IF_ERR_EXIT(CTC_E_INVALID_CONFIG);
            }
        }
        if (temp_finfo1->size < gran && level != 2)
        {
            continue;
        }

        flags_check = sys_acl_keygen_finfo_flags_verify(lchip,
                                                        level, gran, temp_finfo1);
        if (flags_check == FALSE)
        {
            continue;
        }
        
        CTC_BMP_COUNT_RANGE(temp_finfo1->req_bmp,  count2, 0, 32);
        CTC_BMP_COUNT_RANGE(temp_finfo1->ext_bmp,  count3, 0, 32);
        if((count2  ==  count3) || (count2 > count3 && (count2 - count3) >  1 && gran == 1))
        {
            continue;
        }

        num_chunks = temp_finfo1->size / gran;
        ext_offset = ext_cfg->offset;
        if(temp_finfo1->size < gran && level == 2 && (ext_offset%4 == 0 || half))
        {
            half++;
            num_chunks = 1;
        }
        else
        {
            half = SYS_ACL_KEXT_F_HALF_NONE;
        }

        for (chunk = 0; chunk < num_chunks; chunk++)
        {
            CTC_BMP_COUNT_RANGE(temp_finfo1->req_bmp,
                                count, chunk * gran, gran);
            if (count == 0)
            {
                continue;
            }

            if (CTC_BMP_EQ_RANGE(temp_finfo1->req_bmp,
                                 temp_finfo1->ext_bmp,
                                 chunk * gran, gran))
            {
                continue;
            }

            temp_finfo2 = finfo_free_list[lchip];

            if (temp_finfo2 == NULL)
            {
                STS_ACL_IF_ERR_EXIT(CTC_E_INVALID_CONFIG);
            }

            finfo_free_list[lchip] = temp_finfo2->next;
            DUMP_FINFO_COUNT(0);
            temp_finfo2->flags = temp_finfo1->flags;
            temp_finfo2->section = section;
            temp_finfo2->sec_val = (ext_offset + (chunk * gran)) / gran;
            temp_finfo2->pri_ctrl_sel = temp_finfo1->pri_ctrl_sel;
            temp_finfo2->pri_ctrl_sel_val = temp_finfo1->pri_ctrl_sel_val;	
            temp_finfo2->size = gran;
            temp_finfo2->extracted = FALSE;
            temp_finfo2->req_bit_count = half ? gran: count;
            temp_finfo2->l0_section = temp_finfo1->l0_section;
            temp_finfo2->l0_sec_val = temp_finfo1->l0_sec_val;
            temp_finfo2->l0_field_offset =
            temp_finfo1->l0_field_offset + (chunk * gran);
            CTC_BMP_COPY_RANGE(temp_finfo2->req_bmp, 0,
                               temp_finfo1->req_bmp, chunk * gran, gran);
            CTC_BMP_COPY_RANGE(temp_finfo1->ext_bmp, chunk * gran,
                               temp_finfo1->req_bmp, chunk * gran, gran);
            temp_finfo2->prev = temp_finfo1;
            temp_finfo2->prev_offset = chunk * gran;
            temp_finfo2->next = NULL;
            temp_finfo2->half_flag  = half;

            SYS_ACL_DBG_PRINT("T1 part:%d, l:%d, size:%d, req:0x%x, extract:0x%x\n", part, level, temp_finfo1->size, temp_finfo1->req_bmp[0], temp_finfo1->ext_bmp[0]);
            SYS_ACL_DBG_PRINT("T2 part:%d, l:%d, size:%d, req:0x%x, extract:0x%x\n\n", part, level, temp_finfo2->size, temp_finfo2->req_bmp[0], temp_finfo2->ext_bmp[0]);
            /* add the new finfo node to the list in the
            * sorted(descending) order.
            */
            sec_cfg = keygen_md->ext_cfg_db->sec_cfg[section];

            if (sec_cfg->flags & SYS_ACL_KEXT_SEC_PASSTHRU)
            {
                order_type = ORDER_TYPE_END_OF_LIST;
            }
            else
            {
                order_type = ORDER_TYPE_DESCENDING;
            }

            STS_ACL_IF_ERR_EXIT(
            sys_acl_kext_finfo_node_add(lchip, order_type,
                                              temp_finfo2, &temp_finfo_list));
            
            if(half == SYS_ACL_KEXT_F_HALF_HIGH)
            {
                half = SYS_ACL_KEXT_F_HALF_NONE;
            }
        }
    }

    /* Keep only num_ext number of nodes in the finfo list
     * and add the remaining nodes to free list.
     */
     temp_finfo3 = temp_finfo_list;
     temp_finfo2 = NULL;
     while (temp_finfo3 != NULL)
     {
         /* two 2bit bus extract one 4bit bus node */
         if(temp_finfo3->half_flag != SYS_ACL_KEXT_F_HALF_HIGH)
         {
            idx++;
         }
         temp_finfo2 = temp_finfo3;
         temp_finfo3 = temp_finfo3->next;

         if (idx == num_ext)
         {  /* when the last node is half low, need consider if the next is another half node */
            if( temp_finfo2->half_flag == SYS_ACL_KEXT_F_HALF_LOW && 
                temp_finfo3 && temp_finfo3->half_flag == SYS_ACL_KEXT_F_HALF_HIGH)
            {
                continue;
            }
             break;
         }
     }

    SYS_ACL_DBG_PRINT(" gran_left[%d] = %d \n", gran, (num_ext - idx));
     while (temp_finfo3 != NULL)
     {
         temp_finfo4 = temp_finfo3;
         temp_finfo3 = temp_finfo3->next;
         CTC_BMP_CLR_RANGE(temp_finfo4->prev->ext_bmp,
                           temp_finfo4->prev_offset,
                           temp_finfo4->size);

         SYS_ACL_DBG_PRINT("[info3] part:%d, l:%d, size:%d, req:0x%x, extract:0x%x\n", part, level, temp_finfo4->size, temp_finfo4->req_bmp[0], temp_finfo4->ext_bmp[0]);

         sal_memset(temp_finfo4, 0, sizeof(sys_acl_kext_finfo_t));
         temp_finfo4->next = finfo_free_list[lchip];
         finfo_free_list[lchip] = temp_finfo4;
         DUMP_FINFO_COUNT(1);
     }


     /* Add the list of chunks to the section in given level and part. */
     if (temp_finfo2 != NULL)
     {
         temp_finfo2->next = keygen_md->ext_finfo_db[part][level].finfo[section];
         keygen_md->ext_finfo_db[part][level].finfo[section] = temp_finfo_list;
     }

    STS_ACL_FUNC_EXIT();
exit:

    STS_ACL_FUNC_EXIT();
}

STATIC int32
sys_acl_kext_fields_validate(int32 lchip,
                                uint8 part,
                                uint8 level,
                                sys_acl_kext_sec_t section,
                                sys_acl_keygen_md_t *keygen_md)
{
    uint8 efield = 0;
    uint8 ext_part = 0;
    uint16 ext_idx = 0;
    uint16 bit_count = 0;
    sys_acl_kext_cfg_t *ext_cfg = NULL;
    sys_acl_kext_finfo_t *temp_finfo1 = NULL;

    STS_ACL_FUNC_ENTER(lchip);
    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);

    bit_count = SYS_ACL_KEXT_F_WORD_CNT * sizeof(uint32) * 8;
    SYS_ACL_EXT_DBG("part:%u, level:%u, section:%s, conf_size:%u, bit_count:%u, func:%s()\n",
                    part, level, sys_acl_sec_str[section], keygen_md->ext_cfg_db->conf_size[level], bit_count, __FUNCTION__);

    for (ext_idx = 0;  ext_idx < keygen_md->ext_cfg_db->conf_size[level];  ext_idx++)
    {
        ext_cfg =  keygen_md->ext_cfg_db->ext_cfg[level] + ext_idx;
        ext_part =  SYS_ACL_KEXT_ID_PART_GET(ext_cfg->ext_id);
        if (ext_cfg->out_sec != section ||  ext_cfg->in_use == FALSE ||  ext_part != part)
        {
            continue;
        }

        temp_finfo1 = ext_cfg->finfo;

        if (temp_finfo1 == NULL)
        {
            if (CTC_BMP_ISSET(ext_cfg->ext_attrs.w, SYS_ACL_KEXT_ATTR_NOT_WITH_QSET_UPDATE))
            {
                continue;
            }
            else
            {
                SYS_ACL_EXT_DBG("temp_finfo1 is null, ext_idx:%u, line:%u\n", ext_idx, __LINE__);
                STS_ACL_IF_ERR_EXIT(CTC_E_INVALID_CONFIG);
            }
        }

        efield = CTC_BMP_EQ_RANGE(temp_finfo1->req_bmp, temp_finfo1->ext_bmp, 0, bit_count);
        if (!efield)
        {
            STS_ACL_RETURN_VAL_EXIT(CTC_E_NO_RESOURCE);
        }
    }
exit:
    STS_ACL_FUNC_EXIT();
}

#if 0
STATIC void
sys_acl_kext_sec_finfo_reset(int32 lchip,
                                    uint8 part,
                                    uint8 level,
                                    sys_acl_kext_sec_t section,
                                    sys_acl_keygen_md_t *keygen_md)
{
    sys_acl_kext_finfo_t *finfo = NULL;
    sys_acl_kext_finfo_t *temp_finfo = NULL;

    finfo = keygen_md->ext_finfo_db[part][level].finfo[section];

    while (finfo != NULL)
    {
        temp_finfo = finfo;
        finfo = finfo->next;

        CTC_BMP_CLR_RANGE(temp_finfo->prev->ext_bmp,
                          temp_finfo->prev_offset,
                          temp_finfo->size);
    }

    (void)sys_acl_kext_finfo_release(lchip,
            keygen_md->ext_finfo_db[part][level].finfo[section]);

    keygen_md->ext_finfo_db[part][level].finfo[section] = NULL;
}
#endif

STATIC int32
sys_acl_kext_fs_get_next(int32 lchip,
                              uint8 part,
                              uint8 level,
                              sys_acl_keygen_cfg_t *keygen_cfg,
                              sys_acl_keygen_md_t *keygen_md)
{
    uint8 idx = 0;
    uint8 gran = 0;
    uint8 gran_count = 0;
    uint8 sec_idx = 0;
    uint8 num_ext = 0;
    sys_acl_kext_sec_t section;
    sys_acl_kext_sec_gran_t *gran_info = NULL;

    STS_ACL_FUNC_ENTER(lchip);
    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);
    //SYS_ACL_EXT_DBG("part:%u, level:%u, func:%s()\n", part, level+1, __FUNCTION__);

    for (sec_idx = 0; sec_idx < SYS_ACL_KEXT_SECTION_COUNT; sec_idx++)
    {
        section = keygen_md->sections[part][level + 1][sec_idx];
        if (section == SYS_ACL_KEXT_SECTION_DISABLE)
        {
            continue;
        }
        gran_count = keygen_md->section_gran_info[section].out_gran_info_count;
        gran_info = keygen_md->section_gran_info[section].out_gran_info;


        for (idx = 0; idx < gran_count; idx++)
        {
            gran = gran_info[idx].gran;
            num_ext = gran_info[idx].num_extractors;

            STS_ACL_IF_ERR_EXIT(sys_acl_kext_fields_create(lchip, part, level + 1,
                                             section, gran, num_ext,
                                             keygen_cfg, keygen_md));
        }
       
        STS_ACL_IF_ERR_EXIT(sys_acl_kext_fields_validate(lchip, part, level + 1,
                                           section, keygen_md));
    }

exit:
    STS_ACL_FUNC_EXIT();
}

STATIC int32
sys_acl_kext_alloc_1(int32 lchip,
                      uint8 part,
                      sys_acl_keygen_cfg_t *keygen_cfg,
                      sys_acl_keygen_md_t *keygen_md)
{
    uint8 level = 0;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);

    for (level = 0; level < keygen_md->num_ext_levels; level++)
    {
        STS_ACL_IF_ERR_EXIT(sys_acl_kext_finfo_db_free(lchip, part, level, keygen_md));
    }


    STS_ACL_IF_ERR_EXIT(sys_acl_kext_cfg_reset_part(lchip, part, keygen_cfg, keygen_md));
    STS_ACL_IF_ERR_EXIT(sys_acl_kext_finfo_add(lchip, part, keygen_md));
    STS_ACL_IF_ERR_EXIT(sys_acl_kext_codes_validate(lchip, part, keygen_cfg, keygen_md));

    for (level = 0; level < keygen_md->num_ext_levels; level++)
    {
        SYS_ACL_DBG_PRINT("-------------------- level:%d ----------------------\n", level);
        STS_ACL_IF_ERR_EXIT(sys_acl_kext_alloc_2(lchip, part, level, keygen_cfg, keygen_md));
        STS_ACL_IF_ERR_EXIT(sys_acl_kext_fs_get_next(lchip, part, level, keygen_cfg, keygen_md));
    }

exit:
    STS_ACL_FUNC_EXIT();
}


STATIC int32
sys_acl_kfield_id_count_get(int32 lchip,
                            sys_acl_keygen_md_t *keygen_md,
                            sys_acl_keygen_cfg_t *keygen_cfg,
                            uint8 *field_id_count)
{
    int32 bit_count = 0;
    uint8 idx = 0;
    uint8 f_idx = 0;
    uint8 finfo_idx = 0;
    uint8 part = 0;
    uint8 sec_val = 0;
    uint8 field_cfg_id = 0;
    uint16 ctrl_sel_val = 0;
    uint16 field_offset = 0;
    uint16 field_width = 0;
    sys_acl_kext_sec_t section;
    sys_acl_kext_ctrl_sel_t ctrl_sel;
    sys_acl_kext_finfo_t *finfo = NULL;
    sys_acl_field_t field_id = SYS_ACL_FIELD_COUNT;
    sys_acl_kfield_cfg_t *field_cfg = NULL;
    sys_acl_kfield_cfg_info_t *field_cfg_info = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(field_id_count, CTC_E_INVALID_PARAM);

    for (idx = 0; idx < keygen_cfg->field_info_count; idx++)
    {
        field_cfg_id = keygen_md->field_cfg_id_arr[idx];
        field_id = keygen_cfg->field_info_arr[idx].field_id;
        field_cfg_info = keygen_md->field_cfg_info[field_id];
        field_cfg = &(field_cfg_info->field_cfg_arr[field_cfg_id]);

        field_offset = 0;
        for (f_idx = 0; f_idx < field_cfg->num_chunks; f_idx++)
        {
            section = field_cfg->e_params[f_idx].section;
            sec_val = field_cfg->e_params[f_idx].sec_val;
            ctrl_sel = field_cfg->pri_ctrl_sel;
            ctrl_sel_val = field_cfg->pri_ctrl_sel_val;

            if (keygen_cfg->field_info_arr[idx].partial == TRUE)
            {
                field_width = field_cfg->e_params[f_idx].width;
                bit_count = 0;
                CTC_BMP_COUNT_RANGE(keygen_cfg->field_info_arr[idx].bitmap,
                                    bit_count, field_offset, field_width);
                field_offset += field_cfg->e_params[f_idx].width;
                if (bit_count == 0)
                {
                    continue;
                }
            }

            for (finfo_idx = 0;  finfo_idx < SYS_ACL_KEXT_FIELDS_MAX;  finfo_idx++)
            {
                if (section == keygen_md->finfo[finfo_idx].l0_section &&
                    sec_val == keygen_md->finfo[finfo_idx].l0_sec_val &&
                ctrl_sel == keygen_md->finfo[finfo_idx].pri_ctrl_sel &&
                ctrl_sel_val == keygen_md->finfo[finfo_idx].pri_ctrl_sel_val)
                {
                    finfo = &(keygen_md->finfo[finfo_idx]);
                    break;
                }
            }

            STS_ACL_IF_ERR_EXIT((finfo == NULL) ? CTC_E_INVALID_CONFIG : CTC_E_NONE);
            part = finfo->part;
            field_id_count[part]++;
        }
    }

exit:
    STS_ACL_FUNC_EXIT();
}

STATIC int32
sys_acl_kext_fs_get_last(int32 lchip,
                              uint8 part,
                              uint8 level,
                              sys_acl_kext_sec_t section,
                              uint8 sec_val,
                              sys_acl_kext_ctrl_sel_t ctrl_sel,
                              uint16 ctrl_sel_val,
                              sys_acl_keygen_md_t *keygen_md,
                              sys_acl_kext_finfo_t **finfo_list)
{
    uint8 ext_part = 0;
    uint32 ext_idx = 0;
    uint8 loop = 0;
    uint8 i = 0;
    sys_acl_kext_cfg_t *ext_cfg = NULL;
    sys_acl_kext_finfo_t *temp_finfo1 = NULL;
    sys_acl_kext_finfo_t *temp_finfo2 = NULL;
    sys_acl_kext_finfo_t *temp_finfo3 = NULL;
    sys_acl_kext_finfo_t *temp_finfo4 = NULL;
    sys_acl_kext_finfo_t *temp_finfo_list = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(finfo_list, CTC_E_INVALID_PARAM);

    *finfo_list = NULL;
    for (ext_idx = 0;  ext_idx < keygen_md->ext_cfg_db->conf_size[level]; ext_idx++)
    {
         ext_cfg =  keygen_md->ext_cfg_db->ext_cfg[level] + ext_idx;
         ext_part = SYS_ACL_KEXT_ID_PART_GET(ext_cfg->ext_id);

         if (ext_part != part || ext_cfg->in_use == FALSE)
         {
            continue;
         }

         if ((temp_finfo1 = ext_cfg->finfo) == NULL)
         {
            continue;
         }
        i = 0;
        if(temp_finfo1->half_flag == SYS_ACL_KEXT_F_HALF_LOW)
        {
            loop = 2;   /* need consider finfo1 for two half node */
        }
        do{
            if ((i == 1) && (temp_finfo1 = ext_cfg->finfo1) == NULL)
             {
                continue;
             }
          if (temp_finfo1 &&
             section == temp_finfo1->l0_section &&
             sec_val == temp_finfo1->l0_sec_val &&
             ctrl_sel == temp_finfo1->pri_ctrl_sel &&
             ctrl_sel_val == temp_finfo1->pri_ctrl_sel_val)
          {

             temp_finfo2 = finfo_free_list[lchip];

             if (temp_finfo2 == NULL)
             {
                STS_ACL_IF_ERR_EXIT(CTC_E_INVALID_CONFIG);
             }

             finfo_free_list[lchip] = temp_finfo2->next;

             DUMP_FINFO_COUNT(0);

             sal_memcpy(temp_finfo2, temp_finfo1, sizeof(sys_acl_kext_finfo_t));

             temp_finfo2->next = NULL;

             /* New node is the first node in the list. */
             if (temp_finfo_list == NULL)
             {
                temp_finfo_list = temp_finfo2;
                continue;
             }

             /* New node has to be at the head_node of the list. */
             temp_finfo3 = temp_finfo_list;

             if (temp_finfo3->l0_field_offset > temp_finfo2->l0_field_offset)
             {
                 temp_finfo2->next = temp_finfo3;
                 temp_finfo_list = temp_finfo2;
                 continue;
             }

             /* New node has to be some where in the middle of the list. */
             temp_finfo4 = temp_finfo_list;

             while (temp_finfo3 != NULL)
             {
                 if (temp_finfo3->l0_field_offset > temp_finfo2->l0_field_offset)
                 {
                     temp_finfo4->next = temp_finfo2;
                     temp_finfo2->next = temp_finfo3;
                     break;
                 }

                 temp_finfo4 = temp_finfo3;
                 temp_finfo3 = temp_finfo3->next;
             }
             /* New node has to be at the end of the list. */
            if (temp_finfo3 == NULL)
            {
               temp_finfo4->next = temp_finfo2;
            }
        }
      }while(++i < loop);
    }

    *finfo_list = temp_finfo_list;

exit:
    STS_ACL_FUNC_EXIT();
}


STATIC int32
sys_acl_keygen_bit_stream_get(int32 lchip,
                     uint32 *buffer,
                     uint16 start_bit,
                     uint16 size,
                     uint16  *bs_count,
                     uint16 *bs_offset,
                     uint16 *bs_width)
{
    int32 offset = -1;
    uint16 bit = 0;
    uint16 width = 0;
    uint16 end_bit = 0;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(buffer, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(bs_count, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(bs_width, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(bs_offset, CTC_E_INVALID_PARAM);

    width = 0;
    offset = -1;
    *bs_count = 0;
    end_bit = start_bit + size;

    for (bit = start_bit; bit < end_bit; bit++)
    {
        if (CTC_BMP_ISSET(buffer, bit))
        {
            if (offset == -1)
            {
                offset = bit;
            }
            width++;
            if (bit == end_bit - 1)
            {
                bs_offset[*bs_count] = offset;
                bs_width[*bs_count] = width;
                (*bs_count)++;
            }
        }
        else
        {
            if (offset != -1)
            {
                bs_offset[*bs_count] = offset;
                bs_width[*bs_count] = width;
                (*bs_count)++;
                offset = -1;
                width = 0;
            }
        }
    }

exit:
    STS_ACL_FUNC_EXIT();
}


//static uint16 prev_offset[3][4];

STATIC int32
sys_acl_kfield_offset_get(int32 lchip,
                          sys_acl_keygen_cfg_t *keygen_cfg,
                          sys_acl_keygen_oper_t *keygen_oper,
                          sys_acl_keygen_md_t *keygen_md,
                          sys_acl_field_t field_id,
                          sys_acl_kfield_cfg_t *field_cfg)
{
    int32 bit_count = 0;
    uint8 idx = 0;
    uint8 f_idx = 0;
    uint8 bs_idx = 0;
    uint8 qid_idx = 0;
    uint8 finfo_idx = 0;
    uint8 offset_idx = 0;
    uint8 part = 0;
    uint8 level = 0;
    uint8 sec_val = 0;
    uint8 f_width = 0;
    uint8 q_bit = 0;
    uint8 f_bit = 0;
    uint16 f_offset = 0;
    uint16 ctrl_sel_val = 0;
    uint16 bs_count = 0;
    uint16 field_offset = 0;
    uint16 field_width = 0;
    uint16 bs_offset[SYS_ACL_KEXT_F_OFFSET_COUNT] = { 0 };
    uint16 bs_width[SYS_ACL_KEXT_F_OFFSET_COUNT] = { 0 };
    uint32 req_bmp[SYS_ACL_KEXT_F_WORD_CNT] = { 0 };
    uint32 ext_bmp[SYS_ACL_KEXT_F_WORD_CNT] = { 0 };
    uint8 qid_found[SYS_ACL_KEYGEN_ENTRY_PARTS_MAX] = { FALSE };
    sys_acl_kext_sec_t section;
    sys_acl_kext_ctrl_sel_t ctrl_sel;
    sys_acl_kext_cfg_t *ext_cfg = NULL;
    sys_acl_kext_finfo_t *finfo = NULL;
    sys_acl_kext_finfo_t *finfo_list = NULL;
    sys_acl_kfield_offset_t *offset_info = NULL;
    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(field_cfg, CTC_E_INVALID_PARAM);

    for (idx = 0; idx < keygen_cfg->field_info_count; idx++)
    {
        if (keygen_cfg->field_info_arr[idx].field_id == field_id)
        {
            break;
        }
    }

    STS_ACL_IF_ERR_EXIT(
        (idx == keygen_cfg->field_info_count) ? CTC_E_INVALID_CONFIG : CTC_E_NONE);

    for (f_idx = 0; f_idx < field_cfg->num_chunks; f_idx++)
    {
        section = field_cfg->e_params[f_idx].section;
        sec_val = field_cfg->e_params[f_idx].sec_val;
        ctrl_sel = field_cfg->pri_ctrl_sel;
        ctrl_sel_val = field_cfg->pri_ctrl_sel_val;

        if (keygen_cfg->field_info_arr[idx].partial == TRUE)
        {
            field_width = field_cfg->e_params[f_idx].width;
            bit_count = 0;
            CTC_BMP_COUNT_RANGE(keygen_cfg->field_info_arr[idx].bitmap,
                               bit_count, field_offset, field_width);
            field_offset += field_cfg->e_params[f_idx].width;

            if (bit_count == 0)
            {
                continue;
            }
        }

        for (finfo_idx = 0; finfo_idx < SYS_ACL_KEXT_FIELDS_MAX;  finfo_idx++)
        {

            if (section == keygen_md->finfo[finfo_idx].l0_section &&
                sec_val == keygen_md->finfo[finfo_idx].l0_sec_val &&
            ctrl_sel == keygen_md->finfo[finfo_idx].pri_ctrl_sel &&
            ctrl_sel_val == keygen_md->finfo[finfo_idx].pri_ctrl_sel_val)
            {
                finfo = &(keygen_md->finfo[finfo_idx]);
                break;
            }
        }

        STS_ACL_IF_ERR_EXIT((finfo == NULL) ? CTC_E_INVALID_CONFIG : CTC_E_NONE);

        part = finfo->part;
        qid_idx = keygen_oper->field_offset_info[part].size;
        offset_info = &(keygen_oper->field_offset_info[part].offset_arr[qid_idx]);
        keygen_oper->field_offset_info[part].qid_arr[qid_idx] = field_id;

        if (qid_found[part] == FALSE)
        {
            qid_found[part] = TRUE;
        }

        level = keygen_md->num_ext_levels;

        STS_ACL_IF_ERR_EXIT(
            sys_acl_kext_fs_get_last(lchip, part, level,
                                          section, sec_val,
                                          ctrl_sel, ctrl_sel_val,
                                          keygen_md, &finfo_list));

        f_offset = (field_cfg->e_params[f_idx].offset %  field_cfg->e_params[f_idx].size);
        f_width = field_cfg->e_params[f_idx].width;
        sal_memset(req_bmp, 0x0, sizeof(req_bmp));

        if (keygen_cfg->field_info_arr[idx].partial == TRUE)
        {
            q_bit = field_offset - f_width;

            for (f_bit = f_offset; f_bit < (f_offset + f_width); f_bit++)
            {
                if (CTC_BMP_ISSET(keygen_cfg->field_info_arr[idx].bitmap, q_bit))
                {
                    CTC_BMP_SET(req_bmp, f_bit);
                }

                q_bit++;
            }
        }
        else
        {
            CTC_BMP_SET_RANGE(req_bmp, f_offset, f_width);
        }

        finfo = finfo_list;

        while (finfo != NULL)
        {
            /*uint32 g,p,l,i = 0;*/
            ext_cfg = finfo->ext_cfg;

            CTC_BMP_COPY_RANGE(ext_bmp, finfo->l0_field_offset,
                             finfo->req_bmp, 0, finfo->size);
            CTC_BMP_AND_RANGE(ext_bmp, req_bmp, 0,
                             sizeof(uint32) * SYS_ACL_KEXT_F_WORD_CNT * 8,
                             ext_bmp);

            STS_ACL_IF_ERR_EXIT(
                sys_acl_keygen_bit_stream_get(lchip, ext_bmp,
                                     finfo->l0_field_offset,
                                     finfo->size, &bs_count,
                                     bs_offset, bs_width));
            
            for (bs_idx = 0; bs_idx < bs_count; bs_idx++)
            {
                offset_info->offset[offset_idx] = ext_cfg->offset +
                                                  bs_offset[bs_idx] -
                                                  finfo->l0_field_offset + 
                                                  (finfo->half_flag == SYS_ACL_KEXT_F_HALF_HIGH ? finfo->size/2 : 0);   /* half high node need another 2bit offset*/
                offset_info->width[offset_idx] = bs_width[bs_idx];
                offset_info->num_offsets++;
                offset_idx++;
            }

            finfo = finfo->next;
        }

        if (finfo_list != NULL)
        {
            (void)sys_acl_kext_finfo_release(lchip, finfo_list);
            finfo_list = NULL;
        }
    }

    for (part = 0; part < SYS_ACL_KEYGEN_ENTRY_PARTS_MAX; part++)
    {
        if (qid_found[part] == TRUE)
        {
             keygen_oper->field_offset_info[part].size++;
        }
    }

exit:
    STS_ACL_FUNC_EXIT();
}


STATIC int32
sys_acl_kfield_offset_create(int32 lchip,
                             sys_acl_keygen_cfg_t *keygen_cfg,
                             sys_acl_keygen_oper_t *keygen_oper,
                             sys_acl_keygen_md_t *keygen_md)
{
    uint8 idx = 0;
    uint8 part = 0;
    uint8 parts_count = 0;
    uint8 field_cfg_id = 0;
    uint8 field_id_count[SYS_ACL_KEYGEN_ENTRY_PARTS_MAX];
    sys_acl_field_t *qid_arr = NULL;
    sys_acl_kfield_offset_t *offset_arr = NULL;
    sys_acl_field_t field_id = SYS_ACL_FIELD_COUNT;
    sys_acl_kfield_cfg_t *field_cfg = NULL;
    sys_acl_kfield_cfg_info_t *field_cfg_info = NULL;


    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);

    sal_memset(field_id_count, 0, sizeof(uint8) * SYS_ACL_KEYGEN_ENTRY_PARTS_MAX);
    STS_ACL_IF_ERR_EXIT(
        sys_acl_kfield_id_count_get(lchip, keygen_md, keygen_cfg, field_id_count));
    parts_count = keygen_cfg->num_parts;
    SYS_ACL_ALLOC(keygen_oper->field_offset_info,
                      sizeof(sys_acl_kfield_offset_info_t) * parts_count);

    for (part = 0; part < parts_count; part++)
    {
        qid_arr = NULL;
        offset_arr = NULL;
        if (!field_id_count[part])
        {
            continue;
        }
        SYS_ACL_ALLOC(qid_arr,
                      field_id_count[part] * sizeof(sys_acl_field_t));
        keygen_oper->field_offset_info[part].qid_arr = qid_arr;
        SYS_ACL_ALLOC(offset_arr,
                      field_id_count[part] * sizeof(sys_acl_kfield_offset_t));
        keygen_oper->field_offset_info[part].offset_arr = offset_arr;
    }

    /* Go through all fieldifiers */
    for (idx = 0; idx < keygen_cfg->field_info_count; idx++)
    {
        field_cfg_id = keygen_md->field_cfg_id_arr[idx];
        field_id = keygen_cfg->field_info_arr[idx].field_id;
        field_cfg_info = keygen_md->field_cfg_info[field_id];
        field_cfg = &(field_cfg_info->field_cfg_arr[field_cfg_id]);

        STS_ACL_IF_ERR_EXIT(
        sys_acl_kfield_offset_get(lchip, keygen_cfg,
                                       keygen_oper, keygen_md,
                                       field_id, field_cfg));

    }

exit:
    if (ret)
    {
        for (part = 0; part < parts_count; part++)
        {
            mem_free(keygen_oper->field_offset_info[part].qid_arr);
            mem_free(keygen_oper->field_offset_info[part].offset_arr);
        }
        mem_free(keygen_oper->field_offset_info);
    }
    STS_ACL_FUNC_EXIT();

}



STATIC int32
sys_acl_kext_codes_create(int32 lchip,
                             sys_acl_keygen_cfg_t *keygen_cfg,
                             sys_acl_keygen_md_t *keygen_md,
                             sys_acl_keygen_oper_t *keygen_oper)
{
    uint8 part = 0;
    uint8 level = 0;
    uint16 idx = 0;
    uint16 ext_idx = 0;
    uint16 num_ext_codes = 0;
    sys_acl_kext_cfg_t *ext_cfg = NULL;
    sys_acl_kext_sel_t *ext_codes = NULL;
    sys_acl_kext_ctrl_sel_info_t *ext_ctrl_info = NULL;
    sys_acl_kext_finfo_t *finfo = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_oper, CTC_E_INVALID_PARAM);

    for (level = 1; level < (keygen_md->num_ext_levels + 1); level++)
    {
        for (ext_idx = 0;  ext_idx < keygen_md->ext_cfg_db->conf_size[level];  ext_idx++)
        {
            ext_cfg =  keygen_md->ext_cfg_db->ext_cfg[level] + ext_idx;
            if (CTC_BMP_ISSET(ext_cfg->ext_attrs.w, SYS_ACL_KEXT_ATTR_PASS_THRU))
            {
                continue;
            }

            if (CTC_BMP_ISSET(ext_cfg->ext_attrs.w, SYS_ACL_KEXT_ATTR_NOT_WITH_QSET_UPDATE))
            {
                continue;
            }

            if (ext_cfg->in_use == TRUE)
            {
                num_ext_codes++;
            }
        }
    }

    for (part = 0; part < keygen_cfg->num_parts; part++)
    {
        uint8 i = 0;
        ext_codes = &(keygen_md->ext_codes[part]);

        for (i = SYS_ACL_KEXT_CTRL_SEL_START; i < SYS_ACL_KEXT_CTRL_SEL_MAX; i++)
        {
            if (ext_codes->sel_ctl[i] != SYS_ACL_KEXT_SELCODE_DONT_CARE)
            {
                num_ext_codes++;
            }
        }
    }

    STS_ACL_IF_ERR_EXIT((num_ext_codes == 0) ? CTC_E_INVALID_CONFIG : CTC_E_NONE);

    keygen_oper->ext_ctrl_sel_info_count = num_ext_codes;
    SYS_ACL_ALLOC(keygen_oper->ext_ctrl_sel_info,
                      sizeof(sys_acl_kext_ctrl_sel_info_t) * num_ext_codes);


    ext_ctrl_info = keygen_oper->ext_ctrl_sel_info;

    for (level = 1; level < (keygen_md->num_ext_levels + 1); level++)
    {
        for (ext_idx = 0; ext_idx < keygen_md->ext_cfg_db->conf_size[level]; ext_idx++)
        {
            ext_cfg =  keygen_md->ext_cfg_db->ext_cfg[level] + ext_idx;

            if (CTC_BMP_ISSET(ext_cfg->ext_attrs.w,  SYS_ACL_KEXT_ATTR_PASS_THRU))
            {
                continue;
            }

            if (CTC_BMP_ISSET(ext_cfg->ext_attrs.w,  SYS_ACL_KEXT_ATTR_NOT_WITH_QSET_UPDATE))
            {
                continue;
            }

            if (ext_cfg->in_use == TRUE)
            {
                ext_ctrl_info[idx].ctrl_sel = SYS_ACL_KEXT_CTRL_SEL_MULTIPLEXER;
                finfo = ext_cfg->finfo;
                ext_ctrl_info[idx].ctrl_sel_val = finfo->sec_val;
                ext_ctrl_info[idx].ext_num =  SYS_ACL_KEXT_ID_NUM_GET(ext_cfg->ext_id);
                ext_ctrl_info[idx].part =  SYS_ACL_KEXT_ID_PART_GET(ext_cfg->ext_id);
                ext_ctrl_info[idx].level = SYS_ACL_KEXT_ID_LEVEL_GET(ext_cfg->ext_id);
                ext_ctrl_info[idx].gran =  SYS_ACL_KEXT_ID_GRAN_GET(ext_cfg->ext_id);
                idx++;
            }
        }
    }



    for (part = 0; part < keygen_cfg->num_parts; part++)
    {
        uint8 i = 0;
        ext_codes = &(keygen_md->ext_codes[part]);

        for (i = SYS_ACL_KEXT_CTRL_SEL_START; i < SYS_ACL_KEXT_CTRL_SEL_MAX; i++)
        {
            if (ext_codes->sel_ctl[i] != SYS_ACL_KEXT_SELCODE_DONT_CARE)
            {
                ext_ctrl_info[idx].ctrl_sel = i;
                ext_ctrl_info[idx].ctrl_sel_val = ext_codes->sel_ctl[i];
                ext_ctrl_info[idx].part = part;
                idx++;
            }
        }

    }

    STS_ACL_IF_ERR_EXIT((idx != num_ext_codes) ? CTC_E_INVALID_CONFIG : CTC_E_NONE);

exit:
    STS_ACL_FUNC_EXIT();
}

STATIC int32
sys_acl_kext_finfo_list_verify(int32 lchip)
{
    uint16 idx = 0;
    sys_acl_kext_finfo_t *finfo = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    finfo = finfo_free_list[lchip];
    while (finfo != NULL) {
        idx++;
        finfo = finfo->next;
    }

    if (idx != SYS_ACL_KEXT_FINFO_COUNT) {
        STS_ACL_IF_ERR_EXIT(CTC_E_INVALID_CONFIG);
    }

exit:
    STS_ACL_FUNC_EXIT();
}


STATIC int32
sys_acl_kext_alloc(int32 lchip,
                    sys_acl_keygen_cfg_t *keygen_cfg,
                    sys_acl_keygen_oper_t *keygen_oper,
                    sys_acl_keygen_md_t *keygen_md,
                    uint16* p_key_req_bits)
{
    uint8 idx = 0;
    uint8 part = 0;
    uint8 level = 0;
    uint16 size = 0;
    int32 rv = CTC_E_NONE;
    uint8 field_extracted = FALSE;
    sys_acl_kext_sec_t section;
    sys_acl_kext_finfo_t *finfo = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    CTC_ERROR_RETURN(sys_acl_kext_finfo_list_init(lchip));

    size = (sizeof(uint32) * SYS_ACL_KEYGEN_ENTRY_PARTS_MAX * SYS_ACL_KEXT_GRAN_COUNT);

    sal_memset(keygen_md->bits_extracted, 0, size);


    STS_ACL_IF_ERR_EXIT(
    sys_acl_kext_fs_get_first(lchip, keygen_cfg, keygen_md, p_key_req_bits));

    if (keygen_cfg->num_parts == 1)
    {
        for (idx = 0; idx < SYS_ACL_KEXT_FIELDS_MAX; idx++)
        {
            finfo = &(keygen_md->finfo[idx]);
            section = finfo->section;

            if (section == SYS_ACL_KEXT_SECTION_DISABLE)
            {
                break;
            }

            finfo->part = 0;
        }
    }
    else
    {

        for (idx = 0; idx < SYS_ACL_KEXT_FIELDS_MAX; idx++)
        {
            finfo = &(keygen_md->finfo[idx]);
            field_extracted = FALSE;
            section = finfo->section;

            if (section == SYS_ACL_KEXT_SECTION_DISABLE)
            {
                break;
            }

            keygen_md->tried_part_bmp[0] = 0;


            for (part = 0; part < keygen_cfg->num_parts; part++)
            {
                if (finfo->fixed == 0)
                {
                    STS_ACL_IF_ERR_EXIT(
                    sys_acl_kext_part_get(lchip, keygen_cfg,
                                                keygen_md, finfo));
                }

                if (finfo->part < 0)
                {
                    STS_ACL_RETURN_VAL_EXIT(CTC_E_INVALID_CONFIG);
                }


                ret = sys_acl_kext_alloc_1(lchip, finfo->part,
                                                      keygen_cfg, keygen_md);

                if (STS_ACL_FUNC_VAL_IS(CTC_E_NO_RESOURCE))
                {
                    finfo->part = -1;
                    continue;
                }
                else if (STS_ACL_FAILURE(ret))
                {
                    STS_ACL_IF_ERR_EXIT(ret);
                }
                else
                {
                    field_extracted = TRUE;

                    if (finfo->part < 0)
                    {
                        STS_ACL_RETURN_VAL_EXIT(CTC_E_INVALID_CONFIG);
                    }

                    keygen_md->bits_extracted[finfo->part][0] += finfo->size;

                    break;
                }

            }
            if (field_extracted == FALSE)
            {
                SYS_ACL_EXT_DBG("  idx:%u, part=%u, section:%s, line:%u, func:%s()\n",
                                idx, part, sys_acl_sec_str[section], __LINE__, __FUNCTION__);
                ret = CTC_E_NO_RESOURCE;
                STS_ACL_EXIT();
            }
        }
    }


    for (part = 0; part < keygen_cfg->num_parts; part++)
    {
        SYS_ACL_DBG_PRINT("-------------------- part:%d ----------------------\n", part);
        STS_ACL_IF_ERR_EXIT(
        sys_acl_kext_alloc_1(lchip, part, keygen_cfg, keygen_md));
    }

    /* Assign the offsets in the final key for all the fieldifiers. */
    STS_ACL_IF_ERR_EXIT(
    sys_acl_kfield_offset_create(lchip, keygen_cfg, keygen_oper, keygen_md));


    STS_ACL_IF_ERR_EXIT(
    sys_acl_kext_codes_create(lchip, keygen_cfg, keygen_md, keygen_oper));


exit:
    for (part = 0; part < keygen_cfg->num_parts; part++)
    {
        for (level = 0; level < keygen_md->num_ext_levels; level++)
        {
            (void)sys_acl_kext_finfo_db_free(lchip, part, level, keygen_md);
        }
        (void)sys_acl_kext_cfg_reset_part(lchip, part, keygen_cfg, keygen_md);
    }

    rv = sys_acl_kext_finfo_list_verify(lchip);
    mem_free(p_finfo_pool[lchip]);

    if (STS_ACL_FAILURE(rv))
    {
        ret = rv;
    }

    STS_ACL_FUNC_EXIT();
}

STATIC int32
sys_acl_keygen_cfg_md_process(int32 lchip,
                         sys_acl_keygen_cfg_t *keygen_cfg,
                         sys_acl_keygen_oper_t *keygen_oper,
                         sys_acl_keygen_md_t *keygen_md,
                         uint16* p_key_req_bits)
{
    uint8 field_cfg_id = 0;
    uint8 *field_cfg_id_arr = NULL;
    uint16 idx = 0;
    uint32 field_cfg_combinations = 0;
    uint32 field_cfg_combinations_tried = 0;
    int32 rv = CTC_E_NONE;
    sys_acl_field_t field_id = SYS_ACL_FIELD_COUNT;
    sys_acl_kfield_cfg_t *field_cfg1 = NULL;
    sys_acl_kfield_cfg_t *field_cfg2 = NULL;
    sys_acl_kfield_cfg_info_t **field_cfg_info = NULL;
    sys_acl_kfield_cfg_info_db_t *field_cfg_info_db = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);

    field_cfg_info = keygen_md->field_cfg_info;
    field_cfg_info_db = keygen_md->field_cfg_info_db[0];
    field_id = keygen_cfg->field_info_arr[0].field_id;
    field_cfg_id_arr = keygen_md->field_cfg_id_arr;
    field_cfg_combinations = keygen_md->field_cfg_combinations;

    SYS_ACL_DBG_PRINT("Stat gen flex key. ---------------------------------------------------->\n\n\n");
    while (TRUE)
    {

        for (idx = 0; idx < keygen_cfg->field_info_count; idx++)
        {
            field_id = keygen_cfg->field_info_arr[idx].field_id;
            field_cfg1 = field_cfg_info_db->field_cfg_info[field_id]->field_cfg_arr;
            field_cfg_id = field_cfg_id_arr[idx];
            field_cfg2 = &(field_cfg_info[field_id]->field_cfg_arr[field_cfg_id]);
            sal_memcpy(field_cfg1, field_cfg2, sizeof(sys_acl_kfield_cfg_t));
        }

        rv = sys_acl_kext_alloc(lchip, keygen_cfg, keygen_oper, keygen_md, p_key_req_bits);
        if (STS_ACL_FAILURE(rv) && (rv != CTC_E_NO_RESOURCE))
        {
            STS_ACL_IF_ERR_EXIT(rv);
        }
        else if (STS_ACL_SUCCESS(rv))
        {
            break;
        }

        field_cfg_combinations_tried++;

        /* all combinations are tried , but still no success. */
        if (field_cfg_combinations_tried == field_cfg_combinations)
        {
            STS_ACL_IF_ERR_EXIT(rv);
        }

        /* Identify the next configuration of each fieldifer to try with. */
        field_id = keygen_cfg->field_info_arr[0].field_id;

        if (field_cfg_id_arr[0] == field_cfg_info[field_id]->num_field_cfg - 1)
        {

            field_cfg_id_arr[0] = 0;

            idx = 1;

            while (idx < keygen_cfg->field_info_count)
            {
                field_id = keygen_cfg->field_info_arr[idx].field_id;

                if (field_cfg_id_arr[idx] < field_cfg_info[field_id]->num_field_cfg - 1)
                {
                    field_cfg_id_arr[idx]++;
                    break;
                }
                else
                {
                    field_cfg_id_arr[idx] = 0;
                }

                idx++;
            }

        }
        else
        {
            field_cfg_id_arr[0]++;
        }
    }

exit:
    STS_ACL_FUNC_EXIT();
}

STATIC int32
sys_acl_kext_cfg_db_free(int32 lchip, sys_acl_kext_cfg_db_t *ext_cfg_db)
{
    int32 level;
    int32 ext_sec;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(ext_cfg_db, CTC_E_INVALID_PARAM);

    /* Free extractor sec_cfg memory. */
    for (ext_sec = SYS_ACL_KEXT_SECTION_L1E32;
         ext_sec < SYS_ACL_KEXT_SECTION_COUNT;
         ext_sec++) {
        STS_ACL_FREE(ext_cfg_db->sec_cfg[ext_sec]);
    }

    /* Free extractors configuration memory for all levels. */
    for (level = 1; level < SYS_ACL_KEXT_LEVEL_COUNT; level++) {
        STS_ACL_FREE(ext_cfg_db->ext_cfg[level]);
    }

    STS_ACL_FREE(ext_cfg_db);

exit:
    STS_ACL_FUNC_EXIT();

}


STATIC int32
sys_acl_keygen_md_free(int32 lchip,
                     sys_acl_keygen_cfg_t *keygen_cfg,
                     sys_acl_keygen_md_t *keygen_md)
{
    uint8 level = 0;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_md, CTC_E_NONE);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_NONE);

    STS_ACL_FREE(keygen_md->field_cfg_id_arr);


    (void)sys_acl_kfield_cfg_info_free(lchip, keygen_md->field_cfg_info);

    for (level = 0; level < SYS_ACL_KEXT_LEVEL_COUNT; level++)
    {

        if (keygen_md->field_cfg_info_db[level] == NULL)
        {
            continue;
        }

        (void)sys_acl_kfield_cfg_info_db_free(lchip,
                                                   keygen_md->field_cfg_info_db[level]);
        STS_ACL_FREE(keygen_md->field_cfg_info_db[level]);
    }

    if (keygen_md->ext_cfg_db != NULL)
    {
        STS_ACL_IF_ERR_EXIT
        (sys_acl_kext_cfg_db_free(lchip, keygen_md->ext_cfg_db));
    }

exit:
    STS_ACL_FUNC_EXIT();
}


STATIC int32
sys_acl_keygen_cfg_process(int32 lchip,
                        sys_acl_keygen_cfg_t *keygen_cfg,
                        sys_acl_keygen_oper_t *keygen_oper,
                        uint16* p_key_req_bits)
{

    sys_acl_keygen_md_t *keygen_md = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);

    if (keygen_cfg->field_info_count == 0)
    {
        STS_ACL_RETURN_VAL_EXIT(CTC_E_NONE);
    }

    STS_ACL_IF_ERR_EXIT(sys_acl_keygen_md_alloc(lchip, keygen_cfg, &keygen_md));

    STS_ACL_IF_ERR_EXIT(
        sys_acl_keygen_cfg_md_process(lchip, keygen_cfg, keygen_oper, keygen_md, p_key_req_bits));


exit:
    (void)sys_acl_keygen_md_free(lchip, keygen_cfg, keygen_md);
    STS_ACL_FREE(keygen_md);
    STS_ACL_FUNC_EXIT();
}
#if 0
/*��bitmap ת������*/
STATIC int32
sys_acl_grp_keygen_field_info_alloc(int32 lchip,
                              sys_acl_flex_group_t *grp_cfg,
                              sys_acl_keygen_cfg_t *keygen_cfg)
{
    int32 field_id_count = 0;
    uint16 idx = 0;
    uint32 array_size = 0;
    sys_acl_field_t field_id;
    //sys_acl_field_bitmap_t *field_bitmap = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(grp_cfg, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);

    CTC_BMP_COUNT_RANGE(grp_cfg->kset.w,
                       field_id_count,
                       0, SYS_ACL_FIELD_COUNT);
    STS_ACL_IF_ERR_EXIT((field_id_count == 0) ? CTC_E_INVALID_CONFIG : CTC_E_NONE);

    array_size = field_id_count * sizeof(sys_acl_kfield_info_t);
    SYS_ACL_ALLOC(keygen_cfg->field_info_arr,
                array_size);
    keygen_cfg->field_info_count = field_id_count;
    idx = 0;

    CTC_BMP__ITER(grp_cfg->kset.w, SYS_ACL_FIELD_COUNT, field_id)
    {
        if (keygen_cfg->field_cfg_info_db->field_cfg_info[field_id] == NULL)
        {
            SYS_ACL_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "&&&&&& qid:%d %s not exist!!!!!!\n", field_id, ifp_field_str[field_id]);
            STS_ACL_RETURN_VAL_EXIT(CTC_E_NOT_SUPPORT);
        }

        keygen_cfg->field_info_arr[idx].field_id = field_id;
#if 0   /*temporary unuseful*/
        field_bitmap = grp_cfg->field_bitmap;

        while (field_bitmap != NULL)
        {
            if (field_bitmap->field == field_id)
            {
                sal_memcpy(keygen_cfg->field_info_arr[idx].bitmap,
                           field_bitmap->bitmap,
                           sizeof(uint32) * SYS_ACL_KFIELD_BITMAP_MAX_WORDS);

                keygen_cfg->field_info_arr[idx].partial = TRUE;
                break;
            }

            field_bitmap = field_bitmap->next;
        }
#endif
        idx++;
    }

exit:
    STS_ACL_FUNC_EXIT();
}
#endif
/*��bitmap ת������*/
STATIC int32
sys_tmm_acl_flex_keygen_field_info_alloc(int32 lchip,
                              sys_acl_flex_key_t *p_flex_key,
                              sys_acl_keygen_cfg_t *keygen_cfg)
{
    int32 field_id_count = 0;
    uint16 idx = 0;
    uint32 array_size = 0;
    sys_acl_field_t field_id;
    //sys_acl_field_bitmap_t *field_bitmap = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(p_flex_key, CTC_E_INVALID_PARAM);
    STS_ACL_NULL_CHECK(keygen_cfg, CTC_E_INVALID_PARAM);

    CTC_BMP_COUNT_RANGE(p_flex_key->kset.w,
                       field_id_count,
                       0, SYS_ACL_FIELD_COUNT);
    STS_ACL_IF_ERR_EXIT((field_id_count == 0) ? CTC_E_INVALID_CONFIG : CTC_E_NONE);

    array_size = field_id_count * sizeof(sys_acl_kfield_info_t);
    SYS_ACL_ALLOC(keygen_cfg->field_info_arr,
                array_size);
    keygen_cfg->field_info_count = field_id_count;
    idx = 0;

    CTC_BMP__ITER(p_flex_key->kset.w, SYS_ACL_FIELD_COUNT, field_id)
    {
        if (keygen_cfg->field_cfg_info_db->field_cfg_info[field_id] == NULL)
        {
            SYS_ACL_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "&&&&&& qid:%d %s not exist!!!!!!\n", field_id, ifp_field_str[field_id]);
            keygen_cfg->field_info_count--;
            continue;
        }

        keygen_cfg->field_info_arr[idx].field_id = field_id;
#if 0   /*temporary unuseful*/
        field_bitmap = grp_cfg->field_bitmap;

        while (field_bitmap != NULL)
        {
            if (field_bitmap->field == field_id)
            {
                sal_memcpy(keygen_cfg->field_info_arr[idx].bitmap,
                           field_bitmap->bitmap,
                           sizeof(uint32) * SYS_ACL_KFIELD_BITMAP_MAX_WORDS);

                keygen_cfg->field_info_arr[idx].partial = TRUE;
                break;
            }

            field_bitmap = field_bitmap->next;
        }
#endif
        idx++;
    }

exit:
    STS_ACL_FUNC_EXIT();
}

STATIC int32
sys_acl_ext_codes_init(int32 lchip, sys_acl_ext_sel_t *ext_codes)
{
    STS_ACL_FUNC_ENTER(lchip);

    STS_ACL_NULL_CHECK(ext_codes, CTC_E_INVALID_PARAM);

    sal_memset(ext_codes, SYS_ACL_EXT_SELCODE_DONT_CARE, sizeof(sys_acl_ext_sel_t));

exit:
    STS_ACL_FUNC_EXIT();
}


STATIC int32
sys_acl_keygen_oper_free(int32 lchip,
                      uint16 num_parts,
                      sys_acl_keygen_oper_t *keygen_oper)
{
    uint16 part = 0;
    sys_acl_kfield_offset_info_t *offset_info = NULL;

    STS_ACL_FUNC_ENTER(lchip);

    if (keygen_oper == NULL)
    {
        STS_ACL_RETURN_VAL_EXIT(CTC_E_NONE);
    }

    if (keygen_oper->field_offset_info == NULL &&
        keygen_oper->ext_ctrl_sel_info == NULL)
    {
        STS_ACL_IF_ERR_EXIT(CTC_E_NONE);
    }

    if (keygen_oper->field_offset_info != NULL)
    {
        for (part = 0; part < num_parts; part++)
        {
            offset_info = &(keygen_oper->field_offset_info[part]);
            STS_ACL_FREE(offset_info->qid_arr);
            STS_ACL_FREE(offset_info->offset_arr);
        }

        STS_ACL_FREE(keygen_oper->field_offset_info);
    }

    if (keygen_oper->ext_ctrl_sel_info != NULL)
    {
        STS_ACL_FREE(keygen_oper->ext_ctrl_sel_info);
    }

exit:
    STS_ACL_FUNC_EXIT();
}


#if 0
STATIC int32
sys_acl_grp_oper_get(int32 lchip,
                   sys_acl_keygen_oper_t *keygen_oper,
                   sys_acl_flex_group_t *grp_cfg)
{
   uint8 part = 0;
   uint8 gran = 0;
   uint8 level = 0;
   uint8 ext_num = 0;
   uint8 ctrl_sel_val = 0;
   uint8 parts_count = 0;
   uint16 ext_code_idx = 0;
   uint16 field_idx = 0;
   uint16 offset = 0;
   uint16 num_offsets = 0;
   sys_acl_ext_sel_t *grp_ext_code = NULL;
   sys_acl_group_field_offset_info_t *group_field = NULL;
   sys_acl_kfield_offset_info_t *field_offset_info = NULL;
   sys_acl_kext_ctrl_sel_info_t *keygen_ext_code = NULL;

   STS_ACL_FUNC_ENTER(lchip);

   STS_ACL_NULL_CHECK(grp_cfg, CTC_E_INVALID_PARAM);
   STS_ACL_NULL_CHECK(keygen_oper, CTC_E_INVALID_PARAM);

   STS_ACL_IF_ERR_EXIT(
   parts_count = sys_tmm_acl_fk_parts_count(grp_cfg->flags));

   for (part = 0; part < parts_count; part++)
   {
       group_field = &(grp_cfg->field_arr[part]);
       field_offset_info = &(keygen_oper->field_offset_info[part]);
       group_field->size = field_offset_info->size + 1;
       SYS_ACL_ALLOC(group_field->qid_arr,
                   group_field->size * sizeof(sys_acl_field_t));
       SYS_ACL_ALLOC(group_field->offset_arr,
                   group_field->size * sizeof(sys_acl_field_offset_info_t));

       for (field_idx = 0; field_idx < field_offset_info->size; field_idx++)
       {
           group_field->qid_arr[field_idx] = field_offset_info->qid_arr[field_idx];
           num_offsets = 0;

           for (offset = 0; offset < SYS_ACL_KFIELD_OFFSETS_MAX; offset++)
           {
               if (!field_offset_info->offset_arr[field_idx].width[offset])
               {
                   continue;
               }

               group_field->offset_arr[field_idx].offset[offset] = field_offset_info->offset_arr[field_idx].offset[offset];
               group_field->offset_arr[field_idx].width[offset] = field_offset_info->offset_arr[field_idx].width[offset];
               num_offsets++;

               if (num_offsets ==  field_offset_info->offset_arr[field_idx].num_offsets)
               {
                   break;
               }
           }

           group_field->offset_arr[field_idx].num_offsets = (offset + 1);
       }

       {/*place ltid to fixed position*/
           field_idx = field_offset_info->size;
           group_field->qid_arr[field_idx] = SYS_ACL_FIELD_LT_ID + part;
           group_field->offset_arr[field_idx].offset[0] = 64 + (SYS_ACL_EXT_L3_E4_MAX - 1)*4;
           group_field->offset_arr[field_idx].width[0] = 4;

           group_field->offset_arr[field_idx].offset[1] = 64 + 95;
           group_field->offset_arr[field_idx].width[1] = 1;

           group_field->offset_arr[field_idx].num_offsets = 2;
       }

   }

   for (part = 0; part < SYS_ACL_ENTRY_PARTS_MAX; part++)
   {
       sys_acl_ext_codes_init(lchip, &(grp_cfg->ext_codes[part]));
   }

   for (ext_code_idx = 0;  ext_code_idx < keygen_oper->ext_ctrl_sel_info_count; ext_code_idx++)
   {
       keygen_ext_code = &(keygen_oper->ext_ctrl_sel_info[ext_code_idx]);
       part = keygen_ext_code->part;
       gran = keygen_ext_code->gran;
       level = keygen_ext_code->level;
       ext_num = keygen_ext_code->ext_num;
       ctrl_sel_val = keygen_ext_code->ctrl_sel_val;
       grp_ext_code = &(grp_cfg->ext_codes[part]);

       if (keygen_ext_code->ctrl_sel == SYS_ACL_KEXT_CTRL_SEL_MULTIPLEXER)
       {
           if (level == 1)
           {
               if (gran == 32)
               {
                   grp_ext_code->l1_e32_sel[ext_num] = ctrl_sel_val;
               }
               else if (gran == 16)
               {
                   grp_ext_code->l1_e16_sel[ext_num] = ctrl_sel_val;
               }
               else if (gran == 8)
               {
                   grp_ext_code->l1_e8_sel[ext_num] = ctrl_sel_val;
               }
               else if (gran == 4)
               {
                   grp_ext_code->l1_e4_sel[ext_num] = ctrl_sel_val;
               }
               else if (gran == 2)
               {
                   grp_ext_code->l1_e2_sel[ext_num] = ctrl_sel_val;
               }
               else
               {
                   STS_ACL_RETURN_VAL_EXIT(CTC_E_INVALID_CONFIG);
               }
           }
           else if (level == 2)
           {
               if (gran == 16)
               {
                   grp_ext_code->l2_e16_sel[ext_num] = ctrl_sel_val;
               }
               else if (gran == 4)
               {
                   grp_ext_code->l2_e4_sel[ext_num] = ctrl_sel_val;
               }
               else if (gran == 2)
               {
                   grp_ext_code->l2_e2_sel[ext_num] = ctrl_sel_val;
               }
               else if (gran == 1)
               {
                   grp_ext_code->l2_e1_sel[ext_num] = ctrl_sel_val;
               }
               else
               {
                   STS_ACL_RETURN_VAL_EXIT(CTC_E_INVALID_CONFIG);
               }
           }
           else if (level == 3)
           {
               if (gran == 4)
               {
                   grp_ext_code->l3_e4_sel[ext_num] = ctrl_sel_val;
               }
               else if (gran == 2)
               {
                   grp_ext_code->l3_e2_sel[ext_num] = ctrl_sel_val;
               }
               else if (gran == 1)
               {
                   grp_ext_code->l3_e1_sel[ext_num] = ctrl_sel_val;
               }
               else
               {
                   STS_ACL_RETURN_VAL_EXIT(CTC_E_INVALID_CONFIG);
               }
           }
           else
           {
               STS_ACL_RETURN_VAL_EXIT(CTC_E_INVALID_CONFIG);
           }
       }
       else if (keygen_ext_code->ctrl_sel >= SYS_ACL_KEXT_CTRL_SEL_START ||
           keygen_ext_code->ctrl_sel < SYS_ACL_KEXT_CTRL_SEL_MAX)
       {
           grp_ext_code->sel_ctl[keygen_ext_code->ctrl_sel] = keygen_ext_code->ctrl_sel_val;
       }
       else
       {
           STS_ACL_RETURN_VAL_EXIT(CTC_E_INVALID_CONFIG);
       }
   }


   /*LTID*/
   for (part = 0; part < parts_count; part++)
   {
       grp_ext_code = &(grp_cfg->ext_codes[part]);
       grp_ext_code->l1_e8_sel[7] = 10;
       grp_ext_code->l3_e4_sel[20] = 38;
       grp_ext_code->l3_e1_sel[1] = 156;
   }

   exit:
   if (STS_ACL_FUNC_ERR())
   {
       for (part = 0; part < parts_count; part++)
       {
           group_field = &(grp_cfg->field_arr[part]);
           if (group_field->qid_arr != NULL)
           {
               mem_free(group_field->qid_arr);
           }
           if (group_field->offset_arr != NULL)
           {
               mem_free(group_field->offset_arr);
           }
       }
   }

   (void)sys_acl_keygen_oper_free(lchip, parts_count, keygen_oper);
   STS_ACL_FUNC_EXIT();
}
#endif

STATIC int32
sys_tmm_acl_oper_get(int32 lchip,
                   sys_acl_keygen_oper_t *keygen_oper,
                   sys_acl_flex_key_t *p_flex_key)
{
   uint8 part = 0;
   uint8 gran = 0;
   uint8 level = 0;
   uint8 ext_num = 0;
   uint8 ctrl_sel_val = 0;
   uint8 parts_count = 0;
   uint16 ext_code_idx = 0;
   uint16 field_idx = 0;
   uint16 offset = 0;
   uint16 num_offsets = 0;
   sys_acl_ext_sel_t *grp_ext_code = NULL;
   sys_acl_group_field_offset_info_t *group_field = NULL;
   sys_acl_kfield_offset_info_t *field_offset_info = NULL;
   sys_acl_kext_ctrl_sel_info_t *keygen_ext_code = NULL;

   STS_ACL_FUNC_ENTER(lchip);

   STS_ACL_NULL_CHECK(p_flex_key, CTC_E_INVALID_PARAM);
   STS_ACL_NULL_CHECK(keygen_oper, CTC_E_INVALID_PARAM);

   SYS_ACL_KEY_SIZE_TO_PART_NUM(p_flex_key->key_size, parts_count);

   for (part = 0; part < parts_count; part++)
   {
       group_field = &(p_flex_key->field_arr[part]);
       field_offset_info = &(keygen_oper->field_offset_info[part]);
       group_field->size = field_offset_info->size + 1;
       SYS_ACL_ALLOC(group_field->qid_arr,
                   group_field->size * sizeof(sys_acl_field_t));
       SYS_ACL_ALLOC(group_field->offset_arr,
                   group_field->size * sizeof(sys_acl_field_offset_info_t));

       for (field_idx = 0; field_idx < field_offset_info->size; field_idx++)
       {
           group_field->qid_arr[field_idx] = field_offset_info->qid_arr[field_idx];
           num_offsets = 0;

           for (offset = 0; offset < SYS_ACL_KFIELD_OFFSETS_MAX; offset++)
           {
               if (!field_offset_info->offset_arr[field_idx].width[offset])
               {
                   continue;
               }

               group_field->offset_arr[field_idx].offset[offset] = field_offset_info->offset_arr[field_idx].offset[offset];
               group_field->offset_arr[field_idx].width[offset] = field_offset_info->offset_arr[field_idx].width[offset];
               num_offsets++;

               if (num_offsets ==  field_offset_info->offset_arr[field_idx].num_offsets)
               {
                   break;
               }
           }

           group_field->offset_arr[field_idx].num_offsets = (offset + 1);
       }

       {
           field_idx = field_offset_info->size;
           group_field->qid_arr[field_idx] = SYS_ACL_FIELD_LT_ID + part;
           group_field->offset_arr[field_idx].offset[0] = 64 + (SYS_ACL_EXT_L3_E4_MAX - 1)*4;
           group_field->offset_arr[field_idx].width[0] = 4;

           group_field->offset_arr[field_idx].offset[1] = 64 + 95;
           group_field->offset_arr[field_idx].width[1] = 1;

           group_field->offset_arr[field_idx].num_offsets = 2;
       }

   }

   for (part = 0; part < SYS_ACL_ENTRY_PARTS_MAX; part++)
   {
       sys_acl_ext_codes_init(lchip, &(p_flex_key->ext_codes[part]));
   }

   for (ext_code_idx = 0;  ext_code_idx < keygen_oper->ext_ctrl_sel_info_count; ext_code_idx++)
   {
       keygen_ext_code = &(keygen_oper->ext_ctrl_sel_info[ext_code_idx]);
       part = keygen_ext_code->part;
       gran = keygen_ext_code->gran;
       level = keygen_ext_code->level;
       ext_num = keygen_ext_code->ext_num;
       ctrl_sel_val = keygen_ext_code->ctrl_sel_val;
       grp_ext_code = &(p_flex_key->ext_codes[part]);

       if (keygen_ext_code->ctrl_sel == SYS_ACL_KEXT_CTRL_SEL_MULTIPLEXER)
       {
           if (level == 1)
           {
               if (gran == 32)
               {
                   grp_ext_code->l1_e32_sel[ext_num] = ctrl_sel_val;
               }
               else if (gran == 16)
               {
                   grp_ext_code->l1_e16_sel[ext_num] = ctrl_sel_val;
               }
               else if (gran == 8)
               {
                   grp_ext_code->l1_e8_sel[ext_num] = ctrl_sel_val;
               }
               else if (gran == 4)
               {
                   grp_ext_code->l1_e4_sel[ext_num] = ctrl_sel_val;
               }
               else if (gran == 2)
               {
                   grp_ext_code->l1_e2_sel[ext_num] = ctrl_sel_val;
               }
               else
               {
                   STS_ACL_RETURN_VAL_EXIT(CTC_E_INVALID_CONFIG);
               }
           }
           else if (level == 2)
           {
               if (gran == 16)
               {
                   grp_ext_code->l2_e16_sel[ext_num] = ctrl_sel_val;
               }
               else
               {
                   STS_ACL_RETURN_VAL_EXIT(CTC_E_INVALID_CONFIG);
               }
           }
           else if (level == 3)
           {
               if (gran == 4)
               {
                   grp_ext_code->l3_e4_sel[ext_num] = ctrl_sel_val;
               }
               else if (gran == 2)
               {
                   grp_ext_code->l3_e2_sel[ext_num] = ctrl_sel_val;
               }
               else if (gran == 1)
               {
                   grp_ext_code->l3_e1_sel[ext_num] = ctrl_sel_val;
               }
               else
               {
                   STS_ACL_RETURN_VAL_EXIT(CTC_E_INVALID_CONFIG);
               }
           }
           else
           {
               STS_ACL_RETURN_VAL_EXIT(CTC_E_INVALID_CONFIG);
           }
       }
       else if (keygen_ext_code->ctrl_sel >= SYS_ACL_KEXT_CTRL_SEL_START ||
           keygen_ext_code->ctrl_sel < SYS_ACL_KEXT_CTRL_SEL_MAX)
       {
           grp_ext_code->sel_ctl[keygen_ext_code->ctrl_sel] = keygen_ext_code->ctrl_sel_val;
       }
       else
       {
           STS_ACL_RETURN_VAL_EXIT(CTC_E_INVALID_CONFIG);
       }
   }


   /*LTID*/
   for (part = 0; part < parts_count; part++)
   {
       grp_ext_code = &(p_flex_key->ext_codes[part]);
       grp_ext_code->l1_e8_sel[7] = 10;
       grp_ext_code->l3_e4_sel[20] = 38;
       grp_ext_code->l3_e1_sel[1] = 156;
   }

   exit:
   if (STS_ACL_FUNC_ERR())
   {
       for (part = 0; part < parts_count; part++)
       {
           group_field = &(p_flex_key->field_arr[part]);
           if (group_field->qid_arr != NULL)
           {
               mem_free(group_field->qid_arr);
           }
           if (group_field->offset_arr != NULL)
           {
               mem_free(group_field->offset_arr);
           }
       }
   }

   (void)sys_acl_keygen_oper_free(lchip, parts_count, keygen_oper);
   STS_ACL_FUNC_EXIT();
}

#if 0
int32
sys_acl_group_assign_sel_code(int32 lchip, sys_acl_flex_group_t *fg)
{
    int32 group_field_id_count = 0;
    int32 rv = CTC_E_NONE;
    sys_acl_fk_size_mode_t orig_fk_size_mode = 0;
    sys_acl_keygen_cfg_t keygen_cfg;
    sys_acl_keygen_oper_t keygen_oper;
    sys_acl_keygen_mode_t keygen_mode;
    sys_acl_keygen_mode_t keygen_ext_mode;

    STS_ACL_FUNC_ENTER(lchip);

    sal_memset(&keygen_cfg, 0, sizeof(sys_acl_keygen_cfg_t));
    sal_memset(&keygen_oper, 0, sizeof(sys_acl_keygen_oper_t));

    STS_ACL_NULL_CHECK(fg, CTC_E_INVALID_PARAM);

    if (fg->mode == SYS_ACL_FK_SIZE_MODE_SINGLE)
    {
        CTC_ACL_KSET_REMOVE(fg->kset, SYS_ACL_FIELD_LT_ID);
    }
    else if (fg->mode == SYS_ACL_FK_SIZE_MODE_DOUBLE)
    {
        CTC_ACL_KSET_REMOVE(fg->kset, SYS_ACL_FIELD_LT_ID);
        CTC_ACL_KSET_REMOVE(fg->kset, SYS_ACL_FIELD_LT_ID1);
    }
    else if(fg->mode == SYS_ACL_FK_SIZE_MODE_TRIPLE)
    {
        CTC_ACL_KSET_REMOVE(fg->kset, SYS_ACL_FIELD_LT_ID);
        CTC_ACL_KSET_REMOVE(fg->kset, SYS_ACL_FIELD_LT_ID1);
        CTC_ACL_KSET_REMOVE(fg->kset, SYS_ACL_FIELD_LT_ID2);
    }

    CTC_BMP_COUNT_RANGE(fg->kset.w,
                       group_field_id_count,
                       0, SYS_ACL_FIELD_COUNT);

    if (group_field_id_count == 0) {
        STS_ACL_RETURN_VAL_EXIT(CTC_E_INVALID_CONFIG);
    }



    keygen_cfg.field_cfg_info_db = p_usw_acl_master[lchip]->kgn_field_cfg_info_db;

    STS_ACL_IF_ERR_EXIT(sys_acl_grp_keygen_field_info_alloc(lchip, fg, &keygen_cfg));

    if (keygen_cfg.field_cfg_info_db == NULL)
    {
        STS_ACL_RETURN_VAL_EXIT(CTC_E_INVALID_CONFIG);
    }


    if (fg->mode == SYS_ACL_FK_SIZE_MODE_SINGLE)
    {
        fg->flags = SYS_ACL_FK_SPAN_SINGLE_SLICE;

        keygen_mode = SYS_ACL_KEYGEN_MODE_SINGLE;
        keygen_ext_mode = SYS_ACL_KEYGEN_MODE_SINGLE;

    }
    else if(fg->mode == SYS_ACL_FK_SIZE_MODE_DOUBLE)
    {
        fg->flags = SYS_ACL_FK_SPAN_DOUBLE_SLICE;

        keygen_mode = SYS_ACL_KEYGEN_MODE_DOUBLE;
        keygen_ext_mode = SYS_ACL_KEYGEN_MODE_DOUBLE;

    }
    else if(fg->mode == SYS_ACL_FK_SIZE_MODE_TRIPLE)
    {
        fg->flags = SYS_ACL_FK_SPAN_TRIPLE_SLICE;

        keygen_mode = SYS_ACL_KEYGEN_MODE_TRIPLE;
        keygen_ext_mode = SYS_ACL_KEYGEN_MODE_TRIPLE;
    }

    orig_fk_size_mode = fg->mode;

    keygen_cfg.mode = keygen_mode;
    keygen_cfg.ext_cfg_db = p_usw_acl_master[lchip]->kgn_ext_cfg_db_arr[keygen_ext_mode];

    keygen_cfg.num_parts = sys_tmm_acl_fk_parts_count(fg->flags);

    rv = sys_acl_keygen_cfg_process(lchip, &keygen_cfg, &keygen_oper);


    if (rv == CTC_E_INVALID_CONFIG || rv == CTC_E_NO_RESOURCE)
    {
        fg->mode = orig_fk_size_mode;
        STS_ACL_RETURN_VAL_EXIT(rv);
    }
    else if (STS_ACL_SUCCESS(rv))
    {
    }
    else
    {
        STS_ACL_RETURN_VAL_EXIT(rv);
    }

    STS_ACL_IF_ERR_EXIT(rv);

    STS_ACL_IF_ERR_EXIT(sys_acl_grp_oper_get(lchip, &keygen_oper, fg));


    if (fg->mode == SYS_ACL_FK_SIZE_MODE_SINGLE)
    {
        CTC_ACL_KSET_ADD(fg->kset, SYS_ACL_FIELD_LT_ID);
    }
    else if (fg->mode == SYS_ACL_FK_SIZE_MODE_DOUBLE)
    {
        CTC_ACL_KSET_ADD(fg->kset, SYS_ACL_FIELD_LT_ID);
        CTC_ACL_KSET_ADD(fg->kset, SYS_ACL_FIELD_LT_ID1);
    }
    else if(fg->mode == SYS_ACL_FK_SIZE_MODE_TRIPLE)
    {
        CTC_ACL_KSET_ADD(fg->kset, SYS_ACL_FIELD_LT_ID);
        CTC_ACL_KSET_ADD(fg->kset, SYS_ACL_FIELD_LT_ID1);
        CTC_ACL_KSET_ADD(fg->kset, SYS_ACL_FIELD_LT_ID2);
    }

exit:

    if (STS_ACL_FAILURE(rv))
    {
        fg->mode = orig_fk_size_mode;
    }

    /*coverity fix. Resetting the value as it is no more used */
    orig_fk_size_mode = 0;
    STS_ACL_FREE(keygen_cfg.field_info_arr);
    STS_ACL_FUNC_EXIT();
}
#endif

int32
sys_tmm_acl_flex_key_assign_sel_code(uint8 lchip, uint8 size_mode, sys_acl_flex_key_t *p_flex_key)
{
    int32 fk_field_cnt = 0;
    int32 rv = CTC_E_NONE;
    uint16 key_req_bits = 0;
    sys_acl_keygen_cfg_t keygen_cfg;
    sys_acl_keygen_oper_t keygen_oper;
    sys_acl_keygen_mode_t keygen_mode = SYS_ACL_KEYGEN_MODE_SINGLE;
    sys_acl_keygen_mode_t keygen_ext_mode = SYS_ACL_KEYGEN_MODE_SINGLE;

    STS_ACL_FUNC_ENTER(lchip);

    sal_memset(&keygen_cfg, 0, sizeof(sys_acl_keygen_cfg_t));
    sal_memset(&keygen_oper, 0, sizeof(sys_acl_keygen_oper_t));

    STS_ACL_NULL_CHECK(p_flex_key, CTC_E_INVALID_PARAM);

    if (size_mode == SYS_ACL_FK_SIZE_MODE_SINGLE)
    {
        CTC_ACL_KSET_REMOVE(p_flex_key->kset, SYS_ACL_FIELD_LT_ID);
    }
    else if (size_mode == SYS_ACL_FK_SIZE_MODE_DOUBLE)
    {
        CTC_ACL_KSET_REMOVE(p_flex_key->kset, SYS_ACL_FIELD_LT_ID);
        CTC_ACL_KSET_REMOVE(p_flex_key->kset, SYS_ACL_FIELD_LT_ID1);
    }
    else if(size_mode == SYS_ACL_FK_SIZE_MODE_TRIPLE)
    {
        CTC_ACL_KSET_REMOVE(p_flex_key->kset, SYS_ACL_FIELD_LT_ID);
        CTC_ACL_KSET_REMOVE(p_flex_key->kset, SYS_ACL_FIELD_LT_ID1);
        CTC_ACL_KSET_REMOVE(p_flex_key->kset, SYS_ACL_FIELD_LT_ID2);
    }

    CTC_BMP_COUNT_RANGE(p_flex_key->kset.w,
                       fk_field_cnt,
                       0, SYS_ACL_FIELD_COUNT);

    if (fk_field_cnt == 0) {
        STS_ACL_RETURN_VAL_EXIT(CTC_E_INVALID_CONFIG);
    }



    keygen_cfg.field_cfg_info_db = p_usw_acl_master[lchip]->kgn_field_cfg_info_db;

    STS_ACL_IF_ERR_EXIT(sys_tmm_acl_flex_keygen_field_info_alloc(lchip, p_flex_key, &keygen_cfg));

    if (keygen_cfg.field_cfg_info_db == NULL)
    {
        STS_ACL_RETURN_VAL_EXIT(CTC_E_INVALID_CONFIG);
    }


    if (size_mode == SYS_ACL_FK_SIZE_MODE_SINGLE)
    {
        p_flex_key->key_size = CTC_FPA_KEY_SIZE_160;
        keygen_cfg.num_parts = 1;
        keygen_mode = SYS_ACL_KEYGEN_MODE_SINGLE;
        keygen_ext_mode = SYS_ACL_KEYGEN_MODE_SINGLE;

    }
    else if(size_mode == SYS_ACL_FK_SIZE_MODE_DOUBLE)
    {
        p_flex_key->key_size = CTC_FPA_KEY_SIZE_320;
        keygen_cfg.num_parts = 2;
        keygen_mode = SYS_ACL_KEYGEN_MODE_DOUBLE;
        keygen_ext_mode = SYS_ACL_KEYGEN_MODE_DOUBLE;

    }
    else if(size_mode == SYS_ACL_FK_SIZE_MODE_TRIPLE)
    {
        p_flex_key->key_size = CTC_FPA_KEY_SIZE_640;
        keygen_cfg.num_parts = 3;
        keygen_mode = SYS_ACL_KEYGEN_MODE_TRIPLE;
        keygen_ext_mode = SYS_ACL_KEYGEN_MODE_TRIPLE;
    }

    keygen_cfg.mode = keygen_mode;
    keygen_cfg.ext_cfg_db = p_usw_acl_master[lchip]->kgn_ext_cfg_db_arr[keygen_ext_mode];

    rv = sys_acl_keygen_cfg_process(lchip, &keygen_cfg, &keygen_oper, &key_req_bits);
    p_flex_key->key_req_bits = key_req_bits;


    if (rv == CTC_E_INVALID_CONFIG || rv == CTC_E_NO_RESOURCE)
    {
        STS_ACL_RETURN_VAL_EXIT(rv);
    }
    else if (STS_ACL_SUCCESS(rv))
    {
    }
    else
    {
        STS_ACL_RETURN_VAL_EXIT(rv);
    }

    STS_ACL_IF_ERR_EXIT(rv);

    STS_ACL_IF_ERR_EXIT(sys_tmm_acl_oper_get(lchip, &keygen_oper, p_flex_key));


    if (size_mode == SYS_ACL_FK_SIZE_MODE_SINGLE)
    {
        CTC_ACL_KSET_ADD(p_flex_key->kset, SYS_ACL_FIELD_LT_ID);
    }
    else if (size_mode == SYS_ACL_FK_SIZE_MODE_DOUBLE)
    {
        CTC_ACL_KSET_ADD(p_flex_key->kset, SYS_ACL_FIELD_LT_ID);
        CTC_ACL_KSET_ADD(p_flex_key->kset, SYS_ACL_FIELD_LT_ID1);
    }
    else if(size_mode == SYS_ACL_FK_SIZE_MODE_TRIPLE)
    {
        CTC_ACL_KSET_ADD(p_flex_key->kset, SYS_ACL_FIELD_LT_ID);
        CTC_ACL_KSET_ADD(p_flex_key->kset, SYS_ACL_FIELD_LT_ID1);
        CTC_ACL_KSET_ADD(p_flex_key->kset, SYS_ACL_FIELD_LT_ID2);
    }

exit:

    /*coverity fix. Resetting the value as it is no more used */
    STS_ACL_FREE(keygen_cfg.field_info_arr);
    STS_ACL_FUNC_EXIT();
}

#endif

